在Android开发中,我们经常会用到ListView 这个组件,为了将ListView 的内容展示出来,我们会去实现一个Adapter来适配,将Layout中的布局以列表的形式展现到组件中。

    比如,像 GGTalk 安卓版的查找用户功能,会把符合条件的用户都列在下面:

为了达到这个效果,我们需要实现一个自定义的Adapter,而其它地方的ListView也要实现一个Adapter,这些Adapter会有很多重复的代码,非常繁琐,现在我就将重复代码封装到了一个通用的适配器CommonAdapter中,这样,在使用时只要继承CommonAdapter就可以了,如此就避免了大段代码的重复,让代码更简洁易懂。我们先来看看CommonAdapter的定义。  

一.CommonAdapter 实现

  1. public abstract class CommonAdapter<T> extends BaseAdapter {
  2.  
  3. private List<T> dataList;
  4. protected Context context;
  5. protected int item_layoutId=0;
  6. protected HashMap<Integer,Integer> layoutIdMap; //多种itemView时用到。 第一个int对应type类型,第二个int对应 itemlayoutId
  7.  
  8. /**
  9. * 设置单个子模版VIew,
  10. * @param context
  11. * @param datas 绑定的对象集合
  12. * @param item_layoutId 被绑定的视图layoutID
  13. * */
  14. public CommonAdapter(Context context, List<T> datas, int item_layoutId)
  15. {
  16. this.context=context;
  17. this.dataList=datas;
  18. this.item_layoutId=item_layoutId;
  19. }
  20.  
  21. /**
  22. *设置多个子模版VIew, 并配合重写 getItemViewType(int position)来确定是设置哪个模版
  23. * @param context
  24. * @param datas 绑定的对象集合
  25. * @param layoutIdMap 多种itemViewID Map 第一个int对应type类型,第二个int对应 itemlayoutId
  26. */
  27. public CommonAdapter(Context context, List<T> datas, HashMap<Integer,Integer> layoutIdMap)
  28. {
  29. this.context=context;
  30. this.dataList=datas;
  31. this.layoutIdMap=layoutIdMap;
  32. }
  33.  
  34. @Override
  35. public int getViewTypeCount() {
  36. if(this.layoutIdMap==null)
  37. {
  38. return 1;
  39. }
  40. return this.layoutIdMap.size();
  41. }
  42.  
  43. @Override
  44. public int getCount() {
  45. return this.dataList.size();
  46. }
  47.  
  48. @Override
  49. public Object getItem(int position) {
  50. return this.dataList.get(position);
  51. }
  52.  
  53. @Override
  54. public long getItemId(int position) {
  55. return position;
  56. }
  57.  
  58. @Override
  59. public View getView(int position, View convertView, ViewGroup parent) {
  60. int type = getItemViewType(position);
  61. return getConvertView(position,convertView,type);
  62. }
  63.  
  64. private View getConvertView(int position,View convertView,int itemViewType)
  65. {
  66. if(convertView==null)
  67. {
  68. int layoutId =0;
  69. if(this.item_layoutId!=0)
  70. {
  71. layoutId=this.item_layoutId;
  72. }
  73. if (this.layoutIdMap != null) {
  74. layoutId = this.layoutIdMap.get(itemViewType);
  75. }
  76. convertView = LayoutInflater.from(context).inflate(layoutId, null);
  77. }
  78. T t = this.dataList.get(position);
  79. this.setConvertView(convertView,t,itemViewType);
  80. return convertView;
  81. }
  82.  
  83. /**
  84. * 局部更新数据,调用一次getView()方法;Google推荐的做法
  85. *
  86. * @param parent 要更新的listview
  87. * @param position 要更新的位置
  88. */
  89. public void onOneItemChanged(ListView parent, int position) {
  90. /**第一个可见的位置**/
  91. int firstVisiblePosition = parent.getFirstVisiblePosition();
  92. /**最后一个可见的位置**/
  93. int lastVisiblePosition = parent.getLastVisiblePosition();
  94.  
  95. /**在看见范围内才更新,不可见的滑动后自动会调用getView方法更新**/
  96. if ((position >= firstVisiblePosition && position <= lastVisiblePosition)) {
  97.  
  98. /**获取指定位置view对象**/
  99. View view = parent.getChildAt(position - firstVisiblePosition);
  100. getView(position, view, parent);
  101. }
  102. }
  103.  
  104. /**
  105. * 需要去实现的对item中的view的设置操作
  106. *
  107. * @param convertView 转换后的试图
  108. * @param t Model对象
  109. * @param itemViewType 试图类型。对应layoutIdMap中的key
  110. */
  111. protected abstract void setConvertView(View convertView, T t,int itemViewType);
  112. }

说明如下:

(1)泛型参数<T>就是我们要绑定数据Model对象的class类型。

(2)getViewTypeCount()方法会根据HashMap是否为空来识别是传入的单一模版还是多模版.

(3)CommonAdapter还重写了getCount(),getItem(int position),getView,getConvertView等BaseAdapter 的方法,这些方法的代码都基本每个Adapter都是一样的,我们只需关心 setConvertView 这个抽象方法,在子类中重写它,将具体的逻辑和数据的绑定在此即可。

二.使用CommonAdapter

  1. 先建一个类继承CommonAdapter,在构造函数中调用父类的构造方法以初始化数据。实现 setConvertView 方法,将对象的数据绑定到模版上 即可

    1. public class SearchFriendAdapter extends CommonAdapter<OrayUser> {
    2.    /**
    3. * 设置单个子模版VIew,
    4. * @param context
    5. * @param datas 绑定的对象集合
    6. * @param item_layoutId 被绑定的视图layoutID
    7. * */
    8. public SearchFriendAdapter(Context context,List<OrayUser> datas,int item_layoutId)
    9. {
    10. super(context,datas,item_layoutId);
    11. }
    12.   @Override
    13.   protected void setConvertView(View view, OrayUser orayUser,int itemViewType)
    14.   
    15.     ...具体将对象的数据绑定到模版上
    16.   
    17.  
  2. Activity中使用时new 一个Adapter,然后将adapter绑定到 ListView
    1. adapter = new SearchFriendAdapter(this,this.userList,R.layout.friend_child);
    2. listView.setAdapter(adapter);
  3. 更新数据源中的数据同步到View
    1. //有2种方式将数据源同步到View
    2. adapter.notifyDataSetChanged();//全部刷新
    3. adapter.onOneItemChanged(ListView parent, int position);//刷新指定位置的数据 

三. 让CommonAdapter支持多模板

当然CommonAdapter还支持多模版的应用,我们只需将第一步中的Adapter实现稍稍做改动即可

  1. public class ListViewAdapter extends CommonAdapter<ListViewItemModel> {
  2. /**
  3. *设置多个子模版VIew, 并配合重写 getItemViewType(int position)来确定是设置哪个模版
  4. * @param context
  5. * @param datas 绑定的对象集合
  6. * @param layoutIdMap 多种itemViewID Map 第一个int对应type类型,第二个int对应 itemlayoutId
  7. */
  8. public ListViewAdapter(Context context, List<ListViewItemModel> datas, HashMap<Integer,Integer> layoutIdMap)
  9. {
  10. super(context,datas,layoutIdMap);
  11. }
  12. @Override
  13. public int getItemViewType(int position)
  14. {
  15. ListViewItemModel model= (ListViewItemModel)super.getItem(position);
  16. if(model.floatRight)
  17. {
  18. return ;
  19. }
  20. return ;
  21. }
  22. @Override
  23. protected void setConvertView(View view, ListViewItemModel listViewItemModel,int itemViewType) {
  24. //根据itemViewType 的值来识别是哪个模版,以对应给模版绑定数据  
  25. }
  26. }

如上图我们将构造函数的最后一个参数从单一的layoutID 换成了 模版集合的HashMap,再就是多加了 getItemViewType(int position) 方法来返回 具体Model对应的是哪一个模版类型(即hashMap 中的key值),使用时更新数据源中的数据同步到View和上面的单一模版一样使用。(同上2种更新方法)

  1. HashMap<Integer,Integer> layoutMap=new HashMap<>();
  2. layoutMap.put(0,R.layout.listview_item);//key值最好从0开始向上递增,否则可能会找不到key的BUG
  3. layoutMap.put(1,R.layout.listview_right_item);
  4. adapter=new ListViewAdapter(this,models,layoutMap);
  5. listView.setAdapter(adapter);

四.综合实例

最后我们还是以本文开头的查找用户的例子,来更全面地说明CommonAdapter的使用。页面截图如下:

 1.模版布局

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. android:id="@+id/layout"
  5. android:layout_width="wrap_content"
  6. android:layout_height="wrap_content"
  7. android:background="@drawable/selector_item"
  8. android:descendantFocusability="blocksDescendants"
  9. android:gravity="center_vertical"
  10. android:orientation="horizontal"
  11. android:padding="4dp">
  12.  
  13. <ImageView
  14. android:id="@+id/ct_photo"
  15. android:layout_width="@dimen/headImageSize"
  16. android:layout_height="@dimen/headImageSize"
  17. android:layout_margin="5dp"
  18. android:src="@drawable/plus"
  19. />
  20.  
  21. <ImageView
  22. android:id="@+id/ct_status"
  23. android:layout_width="11dip"
  24. android:layout_height="11dip"
  25. android:layout_marginLeft="@dimen/headImageSize"
  26. android:layout_marginTop="@dimen/headImageSize"
  27. android:src='@drawable/status_2' />
  28.  
  29. <LinearLayout
  30. android:layout_width="wrap_content"
  31. android:layout_height="wrap_content"
  32. android:gravity="center_vertical"
  33. android:layout_alignTop="@id/ct_photo"
  34. android:layout_toRightOf="@id/ct_photo"
  35. >
  36.  
  37. <TextView
  38. android:id="@+id/ct_name"
  39. android:layout_width="wrap_content"
  40. android:layout_height="wrap_content"
  41. android:paddingLeft="5dp"
  42. android:paddingRight="5dp"
  43. android:paddingBottom="5dp"
  44. android:paddingTop="0dp"
  45. android:text="name"
  46. android:textColor="@color/dimgrey"
  47. android:textSize="16sp"
  48. android:textStyle="bold" />
  49.  
  50. <TextView
  51. android:id="@+id/ct_describe"
  52. android:layout_width="wrap_content"
  53. android:layout_height="wrap_content"
  54. android:layout_marginLeft="10dp"
  55. android:layout_toRightOf="@id/ct_name"
  56. android:paddingLeft="5dp"
  57. android:paddingRight="5dp"
  58. android:paddingBottom="5dp"
  59. android:paddingTop="0dp"
  60. android:text="describe"
  61. android:textColor="@color/dimgrey"
  62. android:textSize="14sp"
  63. android:visibility="gone" />
  64. </LinearLayout>
  65. <TextView
  66. android:id="@+id/ct_sign"
  67. android:layout_width="wrap_content"
  68. android:layout_height="wrap_content"
  69. android:layout_alignBottom="@id/ct_photo"
  70. android:layout_toRightOf="@id/ct_photo"
  71. android:paddingLeft="5dp"
  72. android:text="sign"
  73. android:singleLine="true"
  74. android:ellipsize="start"
  75. android:textColor="@color/dimgrey"
  76. android:textSize="12sp" />
  77.  
  78. </RelativeLayout>

2.具体继承CommonAdapter实现子类

  1. public class SearchFriendAdapter extends CommonAdapter<OrayUser> {
  2. public SearchFriendAdapter(Context context,List<OrayUser> datas,int item_layoutId)
  3. {
  4. super(context,datas,item_layoutId);
  5. }
  6.  
  7. @Override
  8. protected void setConvertView(View view, OrayUser orayUser,int itemViewType) {
  9. try{
  10. SearchFriendAdapter.ViewHolder holder;
  11. if(view.getTag()==null)
  12. {
  13. holder = new SearchFriendAdapter.ViewHolder(view);
  14. view.setTag(holder);
  15. }
  16. else {
  17. holder = (SearchFriendAdapter.ViewHolder) view.getTag();
  18. }
  19. HeadImgHelper.setUserHeadImg(holder.headImg,orayUser);
  20. if(orayUser.getName().equals(orayUser.getCommentName()))
  21. {
  22. holder.userName.setText(orayUser.getName());
  23. }
  24. else {
  25. holder.userName.setText(orayUser.getCommentName()+"("+ orayUser.getName()+")");
  26. }
  27. String catalogName= ClientGlobalCache.getInstance().getCurrentUser().getCatalogNameByFriend(orayUser.getUserID());
  28. if(!StringHelper.isNullOrEmpty(catalogName))
  29. {
  30. holder.describe.setText("[ "+ catalogName+" ]");
  31. holder.describe.setVisibility(View.VISIBLE);
  32. }
  33. else
  34. {
  35. holder.describe.setText("");
  36. holder.describe.setVisibility(View.GONE);
  37. }
  38. holder.orgName.setText(orayUser.getUserID());
  39. }catch (Exception ex){ex.printStackTrace();}
  40. }
  41.  
  42. private class ViewHolder
  43. {
  44. public ImageView headImg;
  45. public TextView userName;
  46. public TextView describe;
  47. public TextView orgName;
  48.  
  49. public ViewHolder(View view)
  50. {
  51. this.headImg = (ImageView) view.findViewById(R.id.ct_photo);
  52. ImageView statusImg=(ImageView) view.findViewById(R.id.ct_status);
  53. statusImg.setVisibility(View.GONE);
  54. this.userName=(TextView) view.findViewById(R.id.ct_name);
  55. this.orgName=(TextView) view.findViewById(R.id.ct_sign);
  56. this.describe=(TextView) view.findViewById(R.id.ct_describe);
  57. }
  58. }
  59. }

3. Activity类 核心代码

  1. public class SearchFriendActivity extends Activity implements TextView.OnEditorActionListener{
  2. private DrawableEditText input;
  3. private ListView listView;
  4. private TextView search_resultStr;
  5. private List<OrayUser> userList=new ArrayList<OrayUser>() ;
  6. private SearchFriendAdapter adapter;
  7.  
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_search_friend);
  12. this.initView();
  13. }
  14.  
  15. private void initView()
  16. {
  17. TextView pageTitle=(TextView)findViewById(R.id.headerText);
  18. pageTitle.setText("查找用户");
  19. search_resultStr =(TextView) findViewById(R.id.search_resultStr);
  20. listView=(ListView)findViewById(R.id.listview_user);
  21. listView.setOnItemClickListener(this);
  22. adapter = new SearchFriendAdapter(this,this.userList,R.layout.friend_child);
  23. listView.setAdapter(adapter);
  24.  
  25. } /**
  26. * 执行点击搜索指令
  27. * */
  28. private void action_search(String idOrName)
  29. {
  30. List<OrayUser> temp_users=Manager.getInstance().doSearchUser(idOrName);
  31. search_resultStr.setText("没有找到符合条件的用户或群组");
  32. this.setSearchResult(temp_users);
  33. }
  34.  
  35. private void setSearchResult(List<OrayUser> temp_users)
  36. {
  37. this.userList.clear();
  38. if(temp_users==null||temp_users.size()==)
  39. {
  40. search_resultStr.setVisibility(View.VISIBLE);
  41. }
  42. else
  43. {
  44. for (OrayUser orayUser :temp_users) {
  45. if(orayUser.getUserID().equals(ClientGlobalCache.getInstance().getCurrentUser().getUserID()))
  46. {
  47. temp_users.remove(orayUser);
  48. break;
  49. }
  50. }
  51. this.userList.addAll(temp_users) ;
  52. search_resultStr.setVisibility(View.GONE);
  53. }
  54. this.adapter.notifyDataSetChanged();
  55. }
  56. }

Android开发进阶 -- 通用适配器 CommonAdapter的更多相关文章

  1. 《android开发进阶从小工到专家》读书笔记--HTTP网络请求

    No1: 客户端与服务器的交互流程: 1)客户端执行网络请求,从URL中解析出服务器的主机名 2)将服务器的主机名转换成服务器的IP地址 3)将端口号从URL中解析出来 4)建立一条从客户端与Web服 ...

  2. 推荐扔物线的HenCoder Android 开发进阶系列 后期接着更新

    官网地址:http://hencoder.com/ 我来做一次辛勤的搬运工 HenCoder:给高级 Android 工程师的进阶手册 HenCoder Android 开发进阶: 自定义 View ...

  3. android开发进阶学习博客资源

    Android开发者博客推荐 Android入门级 - 罗宪明 http://blog.csdn.net/wdaming1986 Android入门级 - 魏祝林 http://blog.csdn.n ...

  4. Android开发进阶:如何读写Android文件

    Android主要有四大主要组件组成:Activity.ContentProvider.Service.Intent组成.Android文件的运行主要需要读写四大组件的文件.本文将介绍如何读写Andr ...

  5. Androidproject师进阶之路 :《Android开发进阶:从小工到专家》上市啦!

    封面 文件夹1 文件夹2 - 当当购买链接 - 京东购买链接 为什么写这本书 写这本书的念头由来已久了. 或许是从我打算写<Android源代码设计模式解析与实战>那时起就萌生了这个念头, ...

  6. Android开发进阶——自定义View的使用及其原理探索

    在Android开发中,系统提供给我们的UI控件是有限的,当我们需要使用一些特殊的控件的时候,只靠系统提供的控件,可能无法达到我们想要的效果,这时,就需要我们自定义一些控件,来完成我们想要的效果了.下 ...

  7. Android开发之万能适配器

    ListView.GridView等等非常多的东西都需要适配器.而如果开发一个app每一个listview都有写一个Adapter的话,那还怎么愉快的玩游戏.. 什么是ViewHolider以及的用法 ...

  8. android 开发进阶自定义控件 类似 TextView

    开发自定义控件的步骤: 1. 继承View: 2.重写构造函数并构造方法中获得我们自定义的属性. 3. 重写onDraw, 4.重写onMeasure 等函数 一.自定义View的属性,首先在res/ ...

  9. android 开发进阶 自定义控件-仿ios自动清除控件

    先上图: 开发中经常需要自定义view控件或者组合控件,某些控件可能需要一些额外的配置.比如自定义一个标题栏,你可能需要根据不同尺寸的手机定制不同长度的标题栏,或者更常见的你需要配置标题栏的背景,这时 ...

随机推荐

  1. Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6_10.3.x86_64

    在使用gdb调试时出现Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.212.el6_10.3.x86_64提示 解决 ...

  2. openssl 密钥注意

    使用openssl生成的密钥,在对加密字符串进行数字签名的时候,程序一直报错,错误异常: algid parse error, not a sequence​ 其原因是因为,openssl生成的私钥没 ...

  3. python中读取mat文件

    mat数据格式是Matlab的数据存储的标准格式 在python中可以使用scipy.io中的函数loadmat()读取mat文件. import scipy.io as scio path = 'e ...

  4. 吴裕雄--天生自然python学习笔记:Matplotlib 基本绘图

    使用 Matplotlib 组件绘图时,经常要与 Numpy 组件搭配使用 . 使用 Matplotlib 绘图首先要导入 Matplotlib 组件 , 由于大部分绘图功能是在 matplotlib ...

  5. worship|spurs|drowns out|frauds|expell|spray with|deposit|moist|gave a sigh

    to have or show a strong feeling of respect and admiration for God or a god 敬奉,崇拜,信仰(上帝或神) On the is ...

  6. JavaScript学习总结(一)基础部分

    转自:http://segmentfault.com/a/1190000000652749 基本概念 javascript是一门解释型的语言,浏览器充当解释器. js执行引擎并不是一行一行的执行,而是 ...

  7. t分布|F分布|点估计与区间估计联系|

    应用统计学 推断统计需要样本形容总体,就要有统计量.注意必须总体是正态分布,否则统计量的分布不能得到.卡方分布和t分布只要样本大于30都近似于正态分布. t分布和F分布推导及应用(图): 总体比例是π ...

  8. OA|开放获取期刊|掠夺性期刊|DOI|ORCID|图书馆服务|零次文献|信息素质|

    OA|开放获取期刊|掠夺性期刊|DOI|ORCID|图书馆服务|零次文献| 信息检索 信息素质是什么? 信息素质是指一个人的信息需求.信息意识.信息知识.信息道德.信息能力方面的基本素质. Some ...

  9. DP × KMP

    几道用到KMP的DP题: hdu 5763    hdu 3689    hdu 3336    codeforces 494B    codevs 3945 关于KMP的nx数组: 如果在本文中看见 ...

  10. [洛谷P3391] 文艺平衡树 (Splay模板)

    初识splay 学splay有一段时间了,一直没写...... 本题是splay模板题,维护一个1~n的序列,支持区间翻转(比如1 2 3 4 5 6变成1 2 3 6 5 4),最后输出结果序列. ...