«

如何开发一个新闻订阅APP之Android篇(二、从“逛”页面谈谈多种格式listview的实现细节)

时间:2024-3-2 18:10     作者:韩俊     分类: Android


上一篇文章如何开发一个新闻订阅APP之Android篇(一、实现仿微信主界面效果)
介绍了布板主界面的实现,接下来,我想和大家分享一下ListView的一些使用心得。
listview是客户端最最常见的组件之一,它以列表的形式展示一组数据。android对listview做了很好的优化,即使你的list被用来展现成千上万的数据,对于listview来说,只会生成少量的列表项,具体的数量会视你的屏幕可见区域长度和每一个列表项的高度而定。至于实现原理,这里推荐一篇ListView中convertView和ViewHolder的工作原理

一个简单的列表页面java代码实现需要如下:
一个listview
一个adapter
一组待展示数据

但是界面的设计是丰富多样的,通常一个listview可能会需要显示多种不同的格式。这里推荐直接继承BaseAdapter,因为稍微复杂一点的listview,继承BaseAdapter可以支持你自定义列表加载,显示等等细节实现;
特别注意的一点是,其实无论需要展示多少种类型的布局,你都可以在getView中,针对每条数据,生成不同格式的布局;那为什么android还要提供getViewTypeCount和getItemViewType这两个方法来让你在实现多种布局时必须重载呢?
最主要的原因是:配合getView参数中的convertView,重复利用已有的view布局,展示不同的数据。当你实现了上述两个方法后,listview会调用这些函数,确定你需要的不同类型的布局个数,当listview需要显示某一种类型的布局时,它会根据getItemViewType来判断是否已经缓存了相同类型的布局,如果是,则传入convertView,否则,生成一个新的view;
那么问题又来了:为什么要用convertView?唯一的因素是:更快,如果为每一条数据生成一个新的View会耗费很长的时间,用户在上下滑动会造成卡顿现象,
此外,ViewHolder的模式也是为了在切换列表项时,当已经存在一个缓存的view情况下(即convertView不为空),避免使用findViewById带来的性能开销,优化listView的流畅性;
下面是部分代码,newsList是数据列表;

@Override
public int getItemViewType(int position) {
     News news = newsList. get( position) ;
     int type = news. getType() ;
     return type;
}
@Override
public int getViewTypeCount() {
     return TYPE_COUNT;
}

@Override
public int getCount() {
     return newsList. size() ;
}

@Override
public View getView( int position, View convertView, ViewGroup parent ) {
      News news = newsList. get( position) ;
      int type = getItemViewType (position );
      switch (type ) {
      case TYPE_TEXT:
            return getTextConvertView (convertView , parent, news , position );
      case TYPE_PIC:
            return getPicConvertView (convertView , parent, news , position );
      case TYPE_VOTE:
            return getVoteConvertView (convertView , parent, news , position );
      case TYPE_HU_TEXT :
            return getHuTextConvertView (convertView , parent, news , position) ;
      case TYPE_HU_PIC :
            return getHuPicConvertView (convertView , parent, news , position );
      }
      return convertView ;
}

重写getView,个人习惯是根据当前列表项的布局类型,调用不同的方法,这样代码结构看上去比较清晰;
其实究竟要区分多少种不同的类型,取决于你的每一种类型是否是可以扩展布局类型。举例来说:微信朋友圈每一个状态可以显示的图片最多9张,显示类型为3*3。最少则只有文字,需要多少种类型的布局呢?
答案是只需要一种类型的布局。如何实现?
首先,定义好三层linearlayout和9个imageView,每一层包含三个imageView,假设当前列表项只有文字,则将三个linearLayout的visibility都设置为gone;只有一张图片,则将第一层linearlayout和第一个imageView的visibility设置为visible;即显示N张图片,即将相应前N个imageView设置为可见(至于每一层中后续的imageView的visibility是设置为gone还是invisible,取决于你希望显示的图片类型是铺满屏幕,还是固定大小),每超过一行显示个数,则相应设置新的一行linearlayout为visible即可。

而涉及到完全不同的两种布局,比如微信的分享和通过手机发的个人状态两种类型,则需要定义两种类型的布局,这是因为在显示一个刚刚进入屏幕的列表项时,可以直接配合ViewHolder,使用之前已经缓存过的convertView;
下面是效果图,界面滑动效果还是非常流畅的,并且支持了比较丰富的布局类型:

现在稍微好一点的android机型,在listView中加载再多的文字基本不存在任何问题,但是显示图片仍然需要注意内存开销,特别是像上述界面中显示大量图片的场景。下一篇,我将介绍关于图片加载的一些实现细节。
有兴趣的同学也可以去豌豆荚搜索“布板”或扫描二维码下载android的demo版试用看看,欢迎小伙伴们和我一起讨论交流。

标签: android

热门推荐