介绍

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

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

  淘宝地区选择效果

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

  再来一张自己的效果

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

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

  实现分析

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

  1、用来展示的Fragment

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

Java代码
  1. public class AreaFragment extends Fragment implements AdapterView.OnItemClickListener {  
  2.   
  3.     private static final String ARG_PARAM1 = "parentCode";  
  4.     @Bind(R.id.refresh_list_view)  
  5.     ListView mRefreshListView;  
  6.     @Bind(R.id.loadingBar)  
  7.     ProgressBar mLoadingBar;  
  8.   
  9.     private String mParam1;//parentCode参数  
  10.   
  11.     OkHttpClient mOkHttpClient = new OkHttpClient();  
  12.   
  13.     private OnFragmentInteractionListener mListener;  
  14.   
  15.     private AreaAdapter adapter;//地区adapter  
  16.   
  17.     public AreaFragment() {  
  18.     }  
  19.   
  20.     /** 
  21.      * Use this factory method to create a new instance of 
  22.      * this fragment using the provided parameters. 
  23.      * 
  24.      * @param param1 Parameter 1. 
  25.      * @return A new instance of fragment AreaFragment. 
  26.      */  
  27.     public static AreaFragment newInstance(String param1) {  
  28.         AreaFragment fragment = new AreaFragment();  
  29.         Bundle args = new Bundle();  
  30.         args.putString(ARG_PARAM1, param1);  
  31.         fragment.setArguments(args);  
  32.         return fragment;  
  33.     }  
  34.   
  35.     @Override  
  36.     public void onCreate(Bundle savedInstanceState) {  
  37.         super.onCreate(savedInstanceState);  
  38.         if (getArguments() != null) {  
  39.             //获取父地区的code,用来查询子地区  
  40.             mParam1 = getArguments().getString(ARG_PARAM1);  
  41.               
  42.         }  
  43.     }  
  44.   
  45.     @Override  
  46.     public View onCreateView(LayoutInflater inflater, ViewGroup container,  
  47.                              Bundle savedInstanceState) {  
  48.         // Inflate the layout for this fragment  
  49.         View view = inflater.inflate(R.layout.fragment_area, container, false);  
  50.         ButterKnife.bind(this, view);  
  51.         mRefreshListView.setOnItemClickListener(this);  
  52.   
  53.         FormEncodingBuilder builder = new FormEncodingBuilder();  
  54.         builder.add(ARG_PARAM1,mParam1);  
  55.   
  56.         //通过parentCode来请求地区,如果parentCode不存在就是第一级  
  57.         final Request request = new Request.Builder()  
  58.                 .url("http://123.184.16.19:8008/area/list")  
  59.                 .post(builder.build())  
  60.                 .build();  
  61.         mOkHttpClient.newCall(request).enqueue(new Callback(){  
  62.             @Override  
  63.             public void onFailure(Request request, IOException e) {  
  64.   
  65.             }  
  66.   
  67.             @Override  
  68.             public void onResponse(Response response) throws IOException {  
  69.                 final String res = response.body().string();  
  70.                 if (res!=null){  
  71.                     Gson gson = new Gson();  
  72.                     JsonResult jsonResult =  gson.fromJson(res, JsonResult.class);  
  73.                     if (jsonResult.isSuccess()){  
  74.                         List list = (List) jsonResult.getResult();  
  75.   
  76.                         List newList = new ArrayList();  
  77.                         Iterator iterator = list.iterator();  
  78.                         while (iterator.hasNext()){  
  79.                             Map map = (Map) iterator.next();  
  80.                             AreaInfo areaInfo = gson.fromJson(gson.toJson(map),AreaInfo.class);  
  81.                             newList.add(areaInfo);  
  82.                         }  
  83.                         adapter = new AreaAdapter(getContext(),newList);  
  84.                         getActivity().runOnUiThread(new Runnable() {  
  85.                             @Override  
  86.                             public void run() {  
  87.                       //拿到数据进行展示           
  88.                        mRefreshListView.setAdapter(adapter);  
  89.                             }  
  90.                         });  
  91.                     }  
  92.                 }  
  93.             }  
  94.         });  
  95.   
  96.         return view;  
  97.     }  
  98.   
  99.     @Override  
  100.     public void onAttach(Context context) {  
  101.         super.onAttach(context);  
  102.         if (context instanceof OnFragmentInteractionListener) {  
  103.             mListener = (OnFragmentInteractionListener) context;  
  104.         } else {  
  105.             throw new RuntimeException(context.toString()  
  106.                     + " must implement OnFragmentInteractionListener");  
  107.         }  
  108.     }  
  109.   
  110.     @Override  
  111.     public void onDetach() {  
  112.         super.onDetach();  
  113.         mListener = null;  
  114.     }  
  115.   
  116.     @Override  
  117.     public void onDestroyView() {  
  118.         super.onDestroyView();  
  119.         ButterKnife.unbind(this);  
  120.     }  
  121.   
  122.   
  123.   
  124.     @Override  
  125.     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {  
  126.         //单击的时候需要处理地区点击事件,统一交给Activity处理  
  127.         AreaInfo areaInfo = (AreaInfo) parent.getAdapter().getItem(position);  
  128.         if (areaInfo==nullreturn;  
  129.         if (mListener!=null){  
  130.             mListener.onFragmentInteraction(areaInfo);  
  131.         }  
  132.     }  
  133.   
  134.   
  135.     //用来和Activity交互的回调接口  
  136.     public interface OnFragmentInteractionListener {  
  137.         void onFragmentInteraction(AreaInfo areaInfo);  
  138.     }  

  我们用了一个Fragment来接受parentCode,用于请求下一级的地区,获取成功之后进行了展示。并且提供了一个OnFragmentInteractionListener用来在onItemClick时与Activity交互。

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

  2、处理显示效果的adapter

Java代码
  1. class AreaAdapter extends BaseAdapter {  
  2.   
  3.         private List list;  
  4.   
  5.         private int lastPosition;  
  6.   
  7.         public AreaAdapter(Context context, List<AreaInfo> list) {  
  8.             this.list = list;  
  9.         }  
  10.   
  11.   
  12.         @Override  
  13.         public int getCount() {  
  14.             return list.size();  
  15.         }  
  16.   
  17.         @Override  
  18.         public Object getItem(int position) {  
  19.             return list.get(position);  
  20.         }  
  21.   
  22.         @Override  
  23.         public long getItemId(int position) {  
  24.             return 0;  
  25.         }  
  26.   
  27.         @Override  
  28.         public View getView(int position, View convertView, ViewGroup parent) {  
  29.             ViewHolder viewHolder = null;  
  30.             if (convertView==null){  
  31.                convertView =  LayoutInflater.from(getContext()).inflate(R.layout.area_list_item,parent,false);  
  32.                 viewHolder = new ViewHolder();  
  33.                 viewHolder.textView = (TextView) convertView.findViewById(android.R.id.text1);  
  34.                 convertView.setTag(viewHolder);  
  35.             }  
  36.             viewHolder = (ViewHolder) convertView.getTag();  
  37.             AreaInfo item = (AreaInfo) list.get(position);  
  38.             viewHolder.textView.setText(item.getAreaName());  
  39.             if (lastPosition<position&&lastPosition!=0){  
  40.                 ObjectAnimator.ofFloat(convertView,"translationY",convertView.getHeight()*2,0).setDuration(500).start();  
  41.   
  42.             }  
  43.             lastPosition = position;  
  44.             return convertView;  
  45.         }  
  46.   
  47.         class ViewHolder{  
  48.             TextView textView;  
  49.         }  
  50.     }  

  很常见的一个Adapter写法,只是在getView当中获取到了要显示的view,通过

  ObjectAnimator.ofFloat(convertView,"translationY",convertView.getHeight()*2,0).setDuration(500).start()为veiw设置了动画,

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

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

  3、Activity和fragment的交互处理

Java代码
  1. public class AreaSelectActivity extends AppCompatActivity implements AreaFragment.OnFragmentInteractionListener{  
  2.   
  3.     private Fragment oneFragment;  
  4.     private Fragment twoFragment;  
  5.   
  6.   
  7.     private Map map = new HashMap();  
  8.     @Override  
  9.     protected void onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.activity_area_select);  
  12.         ButterKnife.bind(this);  
  13.         //新建第一级地区,parentCode参数为null  
  14.         oneFragment = AreaFragment.newInstance("");  
  15.         FragmentManager fragmentManager = getSupportFragmentManager();  
  16.         fragmentManager.beginTransaction().replace(R.id.content,oneFragment).commit();  
  17.     }  
  18.   
  19.   
  20.     @Override  
  21.     public boolean onOptionsItemSelected(MenuItem item) {  
  22.         switch (item.getItemId()){  
  23.             case android.R.id.home:  
  24.                 FragmentManager fragmentManager = getSupportFragmentManager();  
  25.                 if (fragmentManager.getBackStackEntryCount()>0){  
  26.                     fragmentManager.popBackStack();  
  27.                 }else{  
  28.                     finish();  
  29.                 }  
  30.                 break;  
  31.         }  
  32.         return true;  
  33.     }  
  34.   
  35.   
  36.       
  37.      /** 
  38.      * 处理交互,hide前一个fragment,并且调用addToBackStack让Fragment可以点击back的时候显示前一个fragment 
  39.      * 如果是第三级地区则直接返回地区选择数据给上个Activity 
  40.      * @param areaInfo 被点击的地区信息 
  41.      */  
  42.     @Override  
  43.     public void onFragmentInteraction(AreaInfo areaInfo) {  
  44.         if (areaInfo==null){  
  45.             return;  
  46.         }  
  47.         FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();  
  48.         int level = areaInfo.getLevel();  
  49.         switch (level){  
  50.             case 1:  
  51.                 map.put("provId",areaInfo.getId());  
  52.                 map.put("provName",areaInfo.getAreaName());  
  53.                 if (areaInfo.isLeaf()){  
  54.                     Intent intent = new Intent();  
  55.                     intent.putExtra("addressInfo", (Serializable) map);  
  56.                     setResult(RESULT_OK,intent);  
  57.                     finish();  
  58.                 }else{  
  59.                     transaction.hide(oneFragment);  
  60.                     transaction.add(R.id.content,twoFragment=AreaFragment.newInstance(areaInfo.getAreaCode()+"")).addToBackStack(null).commit();  
  61.                 }  
  62.                 break;  
  63.             case 2:  
  64.                 map.put("cityId",areaInfo.getId());  
  65.                 map.put("cityName",areaInfo.getAreaName());  
  66.                 if (areaInfo.isLeaf()){  
  67.                     Intent intent = new Intent();  
  68.                     intent.putExtra("addressInfo", (Serializable) map);  
  69.                     setResult(RESULT_OK,intent);  
  70.                     finish();  
  71.                 }else {  
  72.                     transaction.hide(twoFragment);  
  73.                     transaction.add (R.id.content, AreaFragment.newInstance(areaInfo.getAreaCode()+"")).addToBackStack(null).commit();  
  74.                 }  
  75.                 break;  
  76.             case 3:  
  77.                 map.put("districtId",areaInfo.getId());  
  78.                 map.put("districtName",areaInfo.getAreaName());  
  79.                 Intent intent = new Intent();  
  80.                 intent.putExtra("addressInfo", (Serializable) map);  
  81.                 setResult(RESULT_OK,intent);  
  82.                 finish();  
  83.                 break;  
  84.         }  
  85.   
  86.     }  
  87. }  

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

  结语

  大家可以自己写测试接口,也可以直接调用我写好的接口:

  http://123.184.16.19:8008/area/list

  源码提供给大家参考:

  Android仿淘宝地区选择

本文发布:Android开发网
本文地址:http://www.jizhuomi.com/android/example/591.html
2016年6月27日
发布:鸡啄米 分类:Android开发实例 浏览: 评论:1