欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

轻松实现Android仿淘宝地区选择功能

程序员文章站 2024-03-02 21:20:16
最近用淘宝客户端的时候,编辑地址的时候有个地区选择的功能。看上面的效果觉得挺酷,滚动的时候,是最后一个从下面飞上来挨着前一个。就自己鼓捣一个出来玩玩。 说了效果可能不太直...

最近用淘宝客户端的时候,编辑地址的时候有个地区选择的功能。看上面的效果觉得挺酷,滚动的时候,是最后一个从下面飞上来挨着前一个。就自己鼓捣一个出来玩玩。

说了效果可能不太直观,下面上两张图看看效果

淘宝地区选择效果

轻松实现Android仿淘宝地区选择功能

再来一张自己的效果

轻松实现Android仿淘宝地区选择功能

gif的效果可能不太好,大家自己用android手机打开淘宝看看

实现分析

展示很简单,listview就可以了。对于动画效果,只需要在getview的时候获取到要展示的view,通过属性动画修改translationy就ok啦。由于地区选择是一个界面,所以这里还用到了fragment的 addtobackstack知识

1、用来展示的fragment

用一个fragment来接受parentcode参数来获取父地区的所有子地区,然后进行显示。这里用fragment来做是因为用activity的话,这样的连续点击都是同一类的界面不太适合。

public class areafragment extends fragment implements adapterview.onitemclicklistener {

 private static final string arg_param1 = "parentcode";
 @bind(r.id.refresh_list_view)
 listview mrefreshlistview;
 @bind(r.id.loadingbar)
 progressbar mloadingbar;

 private string mparam1;//parentcode参数

 okhttpclient mokhttpclient = new okhttpclient();

 private onfragmentinteractionlistener mlistener;

 private areaadapter adapter;//地区adapter

 public areafragment() {
 }

 /**
  * use this factory method to create a new instance of
  * this fragment using the provided parameters.
  *
  * @param param1 parameter 1.
  * @return a new instance of fragment areafragment.
  */
 public static areafragment newinstance(string param1) {
  areafragment fragment = new areafragment();
  bundle args = new bundle();
  args.putstring(arg_param1, param1);
  fragment.setarguments(args);
  return fragment;
 }

 @override
 public void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  if (getarguments() != null) {
   //获取父地区的code,用来查询子地区
   mparam1 = getarguments().getstring(arg_param1);

  }
 }

 @override
 public view oncreateview(layoutinflater inflater, viewgroup container,
        bundle savedinstancestate) {
  // inflate the layout for this fragment
  view view = inflater.inflate(r.layout.fragment_area, container, false);
  butterknife.bind(this, view);
  mrefreshlistview.setonitemclicklistener(this);

  formencodingbuilder builder = new formencodingbuilder();
  builder.add(arg_param1,mparam1);

  //通过parentcode来请求地区,如果parentcode不存在就是第一级
  final request request = new request.builder()
    .url("http://123.184.16.19:8008/area/list")
    .post(builder.build())
    .build();
  mokhttpclient.newcall(request).enqueue(new callback(){
   @override
   public void onfailure(request request, ioexception e) {

   }

   @override
   public void onresponse(response response) throws ioexception {
    final string res = response.body().string();
    if (res!=null){
     gson gson = new gson();
     jsonresult jsonresult = gson.fromjson(res, jsonresult.class);
     if (jsonresult.issuccess()){
      list list = (list) jsonresult.getresult();

      list newlist = new arraylist();
      iterator iterator = list.iterator();
      while (iterator.hasnext()){
       map map = (map) iterator.next();
       areainfo areainfo = gson.fromjson(gson.tojson(map),areainfo.class);
       newlist.add(areainfo);
      }
      adapter = new areaadapter(getcontext(),newlist);
      getactivity().runonuithread(new runnable() {
       @override
       public void run() {
      //拿到数据进行展示   
      mrefreshlistview.setadapter(adapter);
       }
      });
     }
    }
   }
  });

  return view;
 }

 @override
 public void onattach(context context) {
  super.onattach(context);
  if (context instanceof onfragmentinteractionlistener) {
   mlistener = (onfragmentinteractionlistener) context;
  } else {
   throw new runtimeexception(context.tostring()
     + " must implement onfragmentinteractionlistener");
  }
 }

 @override
 public void ondetach() {
  super.ondetach();
  mlistener = null;
 }

 @override
 public void ondestroyview() {
  super.ondestroyview();
  butterknife.unbind(this);
 }


 @override
 public void onitemclick(adapterview<?> parent, view view, int position, long id) {
  //单击的时候需要处理地区点击事件,统一交给activity处理
  areainfo areainfo = (areainfo) parent.getadapter().getitem(position);
  if (areainfo==null) return;
  if (mlistener!=null){
   mlistener.onfragmentinteraction(areainfo);
  }
 }


 //用来和activity交互的回调接口
 public interface onfragmentinteractionlistener {
  void onfragmentinteraction(areainfo areainfo);
 }

我们用了一个fragment来接受parentcode,用于请求下一级的地区,获取成功之后进行了展示。并且提供了一个onfragmentinteractionlistener用来在onitemclick时与activity交互。

接下来看adapter,最开始我们提到了要实现淘宝的效果我们只需要拿到即将显示的view,设置动画就可以了。

2、处理显示效果的adapter

class areaadapter extends baseadapter {

  private list list;

  private int lastposition;

  public areaadapter(context context, list<areainfo> list) {
   this.list = list;
  }


  @override
  public int getcount() {
   return list.size();
  }

  @override
  public object getitem(int position) {
   return list.get(position);
  }

  @override
  public long getitemid(int position) {
   return 0;
  }

  @override
  public view getview(int position, view convertview, viewgroup parent) {
   viewholder viewholder = null;
   if (convertview==null){
    convertview = layoutinflater.from(getcontext()).inflate(r.layout.area_list_item,parent,false);
    viewholder = new viewholder();
    viewholder.textview = (textview) convertview.findviewbyid(android.r.id.text1);
    convertview.settag(viewholder);
   }
   viewholder = (viewholder) convertview.gettag();
   areainfo item = (areainfo) list.get(position);
   viewholder.textview.settext(item.getareaname());
   if (lastposition<position&&lastposition!=0){
    objectanimator.offloat(convertview,"translationy",convertview.getheight()*2,0).setduration(500).start();

   }
   lastposition = position;
   return convertview;
  }

  class viewholder{
   textview textview;
  }
 }

很常见的一个adapter写法,只是在getview当中获取到了要显示的view,通过
objectanimator.offloat(convertview,”translationy”,convertview.getheight()*2,0).setduration(500).start()为veiw设置了动画,

这里还用了个变量position来区别只有在向上滚动的时候才会有动画。不过我觉得不加position区别的效果也不错,大家可以试试。

其实这样已经实现了效果,接下来顺便提一下activity对framgnet中onitemclick的处理。

3、activity和fragment的交互处理

public class areaselectactivity extends appcompatactivity implements areafragment.onfragmentinteractionlistener{

 private fragment onefragment;
 private fragment twofragment;


 private map map = new hashmap();
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_area_select);
  butterknife.bind(this);
  //新建第一级地区,parentcode参数为null
  onefragment = areafragment.newinstance("");
  fragmentmanager fragmentmanager = getsupportfragmentmanager();
  fragmentmanager.begintransaction().replace(r.id.content,onefragment).commit();
 }


 @override
 public boolean onoptionsitemselected(menuitem item) {
  switch (item.getitemid()){
   case android.r.id.home:
    fragmentmanager fragmentmanager = getsupportfragmentmanager();
    if (fragmentmanager.getbackstackentrycount()>0){
     fragmentmanager.popbackstack();
    }else{
     finish();
    }
    break;
  }
  return true;
 }


  /**
  * 处理交互,hide前一个fragment,并且调用addtobackstack让fragment可以点击back的时候显示前一个fragment
  * 如果是第三级地区则直接返回地区选择数据给上个activity
  * @param areainfo 被点击的地区信息
  */
 @override
 public void onfragmentinteraction(areainfo areainfo) {
  if (areainfo==null){
   return;
  }
  fragmenttransaction transaction = getsupportfragmentmanager().begintransaction();
  int level = areainfo.getlevel();
  switch (level){
   case 1:
    map.put("provid",areainfo.getid());
    map.put("provname",areainfo.getareaname());
    if (areainfo.isleaf()){
     intent intent = new intent();
     intent.putextra("addressinfo", (serializable) map);
     setresult(result_ok,intent);
     finish();
    }else{
     transaction.hide(onefragment);
     transaction.add(r.id.content,twofragment=areafragment.newinstance(areainfo.getareacode()+"")).addtobackstack(null).commit();
    }
    break;
   case 2:
    map.put("cityid",areainfo.getid());
    map.put("cityname",areainfo.getareaname());
    if (areainfo.isleaf()){
     intent intent = new intent();
     intent.putextra("addressinfo", (serializable) map);
     setresult(result_ok,intent);
     finish();
    }else {
     transaction.hide(twofragment);
     transaction.add (r.id.content, areafragment.newinstance(areainfo.getareacode()+"")).addtobackstack(null).commit();
    }
    break;
   case 3:
    map.put("districtid",areainfo.getid());
    map.put("districtname",areainfo.getareaname());
    intent intent = new intent();
    intent.putextra("addressinfo", (serializable) map);
    setresult(result_ok,intent);
    finish();
    break;
  }

 }
}

这样仿淘宝地区选择就实现啦!

结语

大家可以自己写测试接口,也可以直接调用我写好的接口: http://123.184.16.19:8008/area/list

源码提供给大家参考:android仿淘宝地区选择

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。