当前位置: 移动技术网 > 移动技术>移动开发>Android > 轻松实现Android仿淘宝地区选择功能

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

2019年07月24日  | 移动技术网移动技术  | 我要评论
最近用淘宝客户端的时候,编辑地址的时候有个地区选择的功能。看上面的效果觉得挺酷,滚动的时候,是最后一个从下面飞上来挨着前一个。就自己鼓捣一个出来玩玩。 说了效果可能不太直

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

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

淘宝地区选择效果

淘宝

再来一张自己的效果

这里写图片描述

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

源码提供给大家参考:

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

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网