一般来说,ListView的列表项都会采用相同的布局,只是填充的内容不同而已,这种情况下,Android提供了convertView帮我们缓存列表项,达到循环利用的目的,开发者也会使用ViewHolder模式来对ListView进行优化。但有的情况下,ListView的列表项布局是不尽相同的,甚至差别很大,这时就不能简单的使用同一个布局资源文件来表示不同类型的列表项了,而是必须区别对待。典型的情况如Android状态通知栏,如下图所示。

360安全卫士、唱吧,闪推这三款应用在状态通知栏的布局差别很大,那么我们又想使用同一个Adapter来表示不同列表项,这时就需要在Adapter中使用容器来包含这些不同的View了。这里定义SackOfViewAdapter类,继承BaseAdapter,在该类中定义容器变量mViewList来存储ListView中不同列表项的view;同时,定义两个构造函数,一个是在参数中指定容器的大小,并填充null值;一个则直接传入ListView列表项中所有view的集合。代码如下:

SackOfViewAdapter类的关键代码在newView函数和getView函数,其中newView函数用于给容器变量mViewList中值为null的元素赋值,一般由SackOfViewAdapter的子类实现。而getView函数重写自BaseAdapter类,是Adapter返回View类实例的关键函数,代码如下所示:

SackOfViewAdapter类的完整代码如下所示:

  1. public class SackOfViewsAdapter extends BaseAdapter {
  2. private List<View> mViewList = null;
  3. /**
  4. * 构造大小为count,值为null的view集合,这时需要子类重写newView函数
  5. */
  6. public SackOfViewsAdapter(int count) {
  7. super();
  8. mViewList = new ArrayList<View>(count);
  9. for (int i = 0; i < count; i++) {
  10. mViewList.add(null);
  11. }
  12. }
  13. /**
  14. * 由传入的view集合直接给容器赋值,如果view集合中有为null值的view,则子类必须实现newView函数
  15. */
  16. public SackOfViewsAdapter(List<View> views) {
  17. super();
  18. this.mViewList = views;
  19. }
  20. /**
  21. * 返回对应位置的列表项
  22. */
  23. @Override
  24. public Object getItem(int position) {
  25. return mViewList.get(position);
  26. }
  27. /**
  28. * 返回列表项的个数
  29. */
  30. @Override
  31. public int getCount() {
  32. return mViewList.size();
  33. }
  34. /**
  35. * getView函数创建的列表项类型个数
  36. */
  37. @Override
  38. public int getViewTypeCount() {
  39. return getCount();
  40. }
  41. /**
  42. * getView函数创建的view类型值,这里以view所在的位置作为类型值
  43. */
  44. @Override
  45. public int getItemViewType(int position) {
  46. return position;
  47. }
  48. /**
  49. * 如果Adapter中所有列表项都是可点击和可选择的,则返回true
  50. */
  51. @Override
  52. public boolean areAllItemsEnabled() {
  53. return false;
  54. }
  55. /**
  56. * 如果position所指的列表项不是分隔符,则返回true
  57. */
  58. @Override
  59. public boolean isEnabled(int position) {
  60. return false;
  61. }
  62. /**
  63. * 返回指定位置position的列表项的view
  64. */
  65. @Override
  66. public View getView(int position, View convertView, ViewGroup parent) {
  67. View result = mViewList.get(position);
  68. // 如果mViewList中的view为null,则需要调用newView函数来创建一个,该函数由子类来实现
  69. if (result == null) {
  70. result = newView(position, parent);
  71. mViewList.set(position, result);
  72. }
  73. return result;
  74. }
  75. /**
  76. * 创建列表中指定位置的列表项,该函数有子类实现
  77. */
  78. protected View newView(int position, ViewGroup parent) {
  79. throw new RuntimeException("You must override newView()!");
  80. }
  81. /**
  82. * 获得指定位置的列表项的id
  83. */
  84. @Override
  85. public long getItemId(int position) {
  86. return position;
  87. }
  88. /**
  89. * 判断Adapter中是否存在某个指定的view
  90. */
  91. public boolean hasView(View v) {
  92. return mViewList.contains(v);
  93. }
  94. }

最后,以一个实例来说明SackOfViewAdapter类的使用方法,实例中我们定义4个不同布局的列表项,其中一个为null值,由SackOfViewAdapter的子类重写newView函数实现赋值,其他三个则不是null值。这四个view的布局文件分别是main_notify.xml、update_progress_notify.xml、notification_battery.xml和main_notify_red.xml,这些资源借用自360手机卫士,实例效果如下图所示:

而实例的代码如下:

  1. public class SackOfViewsDemo extends ListActivity {
  2. @Override
  3. public void onCreate(Bundle bundle) {
  4. super.onCreate(bundle);
  5. requestWindowFeature(Window.FEATURE_NO_TITLE);
  6. setContentView(R.layout.main);
  7. ArrayList<View> views = new ArrayList<View>();
  8. LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  9. // 列表项1
  10. View view = inflater.inflate(R.layout.main_notify, null);
  11. views.add(view);
  12. // 列表项2
  13. view = inflater.inflate(R.layout.update_progress_notify, null);
  14. views.add(view);
  15. // 列表项3
  16. view = inflater.inflate(R.layout.notification_battery, null);
  17. views.add(view);
  18. // 列表项4(为null值,在newView函数中创建)
  19. views.add(null);
  20. setListAdapter(new SillyAdapter(views));
  21. }
  22. class SillyAdapter extends SackOfViewsAdapter {
  23. public SillyAdapter(List<View> views) {
  24. super(views);
  25. }
  26. protected View newView(int position, ViewGroup parent) {
  27. LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  28. View view = inflater.inflate(R.layout.main_notify_red, null);
  29. return view;
  30. }
  31. }
  32. }

本文的SackOfViewAdapter类参考自 https://github.com/commonsguy/cwac-sacklist

本文源码参见:http://download.csdn.net/detail/ace1985/4575749

Android开源代码解读-基于SackOfViewAdapter类实现类似状态通知栏的布局的更多相关文章

  1. Android开源代码解读のOnScrollListener实现ListView滚屏时不加载数据

    使用ListView过程中,如果滚动加载数据的操作比较费时,很容易在滚屏时出现屏幕卡住的现象,一个解决的办法就是不要在滚动时加载数据,而是等到滚动停止后再进行数据的加载.这同样要实现OnScrollL ...

  2. material design 的android开源代码整理

    material design 的android开源代码整理 1 android (material design 效果的代码库) 地址请点击:MaterialDesignLibrary 效果: 2 ...

  3. android开源代码

    Android开源项目--分类汇总 转自:https://github.com/Trinea/android-open-project Android开源项目第一篇——个性化控件(View)篇 包括L ...

  4. 160多个android开源代码汇总

    第一部分 个性化控件(View) 主要介绍那些不错个性化的View,包括ListView.ActionBar.Menu.ViewPager.Gallery.GridView.ImageView.Pro ...

  5. 优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案

    简介 本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发 ...

  6. Github上不错的Android开源代码(一)

    总有一些朋友很热心的整理一些好的资料,在收集之后,可以用作阅读.学习和实践.小伙伴们,总有一天,你也能写出 Niubility 的 Android App :-) 为了防止以上链接失效,以及部分内容丢 ...

  7. Hybrid----优秀开源代码解读之JS与iOS Native Code互调的优雅实现方案-备

    本篇为大家介绍一个优秀的开源小项目:WebViewJavascriptBridge. 它优雅地实现了在使用UIWebView时JS与ios 的ObjC nativecode之间的互调,支持消息发送.接 ...

  8. 22个值得收藏的Android开源代码-UI篇

    本文介绍了android开发者中比较热门的开源代码,这些代码绝大多数可以直接应用到项目中. FileBrowserView 一个强大的文件选择控件.界面比较漂亮,使用也很简单.特点:可以自定义UI:支 ...

  9. 22个值得收藏的Android开源代码——cool

    转自http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/1020/1808.html 本文介绍了android开发者中比较热门的开源代 ...

随机推荐

  1. Word02-隐藏回车换行符

    Word文档中每次输入回车后,会显示一个换行标志符,影响页面显示效果. 如下图,换行符隐藏前后: 设置方法:(选项-->显示-->段落标记前面的√去掉即可)

  2. centos7编译安装MySQL5.7.9

    title: centos7编译安装MySQL5.7.9 date: 2016-05-12 16:20:17 tags: --- Centos7编译安装mysql5.7.9 mysql5.7有更好的性 ...

  3. mybati之day02

    今天开始讲解mybatis的第二天内容  一,拼接sql 在mapper.xml中,会多次使用到同一条sql片段,这时为了简便书写,将其定义出来 <sql id="base_sql&q ...

  4. C#中的一些技巧

    VS编辑器的虚线如何设置和取消:使用快捷键Ctrl+E+C VS自带的反编译工具是什么:il dasm

  5. spring项目中监听器作用-ContextLoaderListener(项目启动时,加载一些东西到缓存中)

    作用:在启动Web容器时,自动装配Spring applicationContext.xml的配置信息. 因为它实现了ServletContextListener这个接口,在web.xml配置这个监听 ...

  6. @Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction

    1.带有Render的方法返回值是void,在方法内部进行输出: 不带的返回值类型为MvcHtmlString,所以只能这样使用: @Html.Partial 对应 @{Html.RenderPart ...

  7. C++从多n个数中选取m个数的组合

    //start 是从哪个开始取, picked代表已经取了多少个数 //process和data是全局变量数组 //语言说明比较难,我举个例子吧 //从[ 1, 2, 3, 4 ]中选取 2 个数 / ...

  8. C++编译指令#pragma pack的配对使用

    #pragma pack可以用来指定C++数据结构的成员变量的内存对齐数值(可选值为1,2,4,8,16). 本文主要是强调在你的头文件中使用pack指令要配对使用,以避免意外影响项目中其他源文件的结 ...

  9. HDU4545+计算日期

    /* 计算过了D天后的日期 之前D天的日期 */ #include<stdio.h> int judge_year( int year ){ if( (year%4==0&& ...

  10. 使用SQL除掉文本中特殊的ascll字符比如Enter,Tab,空格键

    一.在SQL查询的字段中如果包含tab.enter.空格键,可以使用ascii码进行替换: --替换了文本中含有tab键,Enter键,空格键的ascii码 select REPLACE(REPLAC ...