介绍

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

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

淘宝地区选择效果

再来一张自己的效果

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仿淘宝地区选择

如果对你有帮助的话,动动手点个赞给个评论支持一下。

期待你的关注

最新文章

  1. Java发展历史
  2. 吃透Javascript数组操作的正确姿势—再读《Js高程》
  3. Shader实例:2D流光
  4. Java的CLASSPATH,趁还没忘赶紧写点
  5. Android init.rc执行顺序
  6. [jQuery]最新的 3.0 已发布
  7. ASP.Net数据导出Excel的几种方法
  8. Tomcat虚拟主机配置
  9. 好博客分享 go需要运行容器? 不需要
  10. MBProgressHUD详解
  11. 使用apache反向代理tomacat
  12. O2O网站
  13. poweshell批量删除某类型文件
  14. TI Davinci DM6446开发攻略——UBL移植
  15. 【翻译】使用Sencha Touch开发Google Glass应用程序
  16. 企业微信快捷接入Odoo的模块——WeOdoo
  17. docker安装redis
  18. linux下列出所有连接到你的Server的IP地址
  19. 采石厂管理系统V3.0版本上线(采石厂车辆出入管理系统,石厂开票系统)
  20. 短网址服务(TinyURL)生成算法

热门文章

  1. .NET平台开源项目速览(7)关于NoSQL数据库LiteDB的分页查询解决过程
  2. ASP.NET Core 中的依赖注入 [共7篇]
  3. 《ASP.NET MVC 5框架揭秘》样章发布
  4. BAT及各大互联网公司2014前端笔试面试题--JavaScript篇
  5. MyCAT日志分析
  6. geotrellis使用(三)geotrellis数据处理过程分析
  7. 基于DDD + SD.Framework实现的统一身份认证系统
  8. 遍历迭代map的集中方法
  9. windows8.1 安装Redis
  10. [java] 深入理解内部类: inner-classes