Android ListView 技巧设置固定可滚动头部

二,在ListView中显示不同的ITEM

阅读本节,默认读者已经了解基本的ListView的优化技巧: ViewHolder, ConvertView

前边提到Ophone的ListView实现中有一个BUG。在我开发的过程中,使用了ListView的Header,放置两个按钮用来跳转到推荐的内容和“掌上应用汇”中的类似,它有4个按键用来导航到推荐的内容。‍‍

Android ListView 技巧设置固定可滚动头部_第1张图片

我使用的设备有5维的导航键,如果你一直用手操作,是不会出现任何问题的,因为手机一直处于TOUCH-MODE,如果用导航键,就会切换到NONE-TOUCH-MODE,不断按向下键切换到HEADER不可见,然后再不断按向上键切换到HEADER可见,这时上图中的4个按钮就会出现问题,表现为无法再收到onClick事件,而且按钮的按下的背景也无法显示(在正常的情况下一个按钮被按下时,会有黄色高亮)。在我的应用和“掌上应用汇”中都可以重现这个问题。可见Ophone中的ListView在处理HEADER View时存在bug,同样的应用程序在HTC Desire with MIUI上表现正常。

你可以使用本节介绍的内容来跳过这个bug,把要显示的View做为List中的第一个ITEM来模拟header效果。

而且我们的最终目标是

Android ListView 技巧设置固定可滚动头部_第2张图片

可以看到图中包含3中不同的ITEM

a) 灰色的title部分

b) 普通的条目

c) 当前title中更为详细”更多“

因为在ListView调用Adapter的

1
public  View getView( int  position, View convertView, ViewGroup parent);

方法时,会把已经不可见的条目传回来,这样的好处是你不用创建一个新的View,只要使用传入的View,更新上面的内容就可以了,这样做可以大大的节约内存资源。

使用的方法就是判断convertView是否为null,如果不为null就使用,如果为null就创建新的。

在我未了解Adapter的机制前,为了实现返回3种不同的View,我写了一个FrameLayout,里面同时有这3种ITEM,只是根据不同的类型来改变不同View的setVisibility为GONE或者VISIBLE。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public  View getView( int  position, View convertView, ViewGroup parent){
   if (convertView ==  null ){
     // 创建一个包含title, normal, more的整个的view
     convertView = inflater.inflate(R.layout.layout, parent,  false );
     holder=  new  ViewHolder();
     holder.title = convertView.findViewById(R.id.title);
      // 省略的内容
     convertView.setTag(holder);
   else  {
     holder= (ViewHolder)convertView.getTag();
   }
   Item item = getItem(position);
   switch (item.getType()){
     case  TITLE:
       holder.title.setVisibility(VISIBLE);
       holder.normal.setVisibility(GONE);
       holder.more.setVisibility(GONE);
       holder.title.setText(item.title);
     break ;
     // 省略的内容
   }
}


通过这种方法也能实现,而且使用convertView,效率也不算太差。缺点也很明显,明明创建了3套View,只是使用其中的1/3,如果有更多种,那就更浪费了。

其实ListView和Adapter早就已经为这种情况考虑到了,ListView在传回convertView时已经考虑到,对于不同的类型就缓存在不同的队列中,在调用时传回。请参考Adapter的如下方法:

1
2
public  int  getViewTypeCount();
public  int  getItemViewType( int  position);

所以我们只要修改下adapter的实现就可以节约不少的资源。

修改后的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public  int  getViewTypeCount(){
   return  TOTAL_TYPE_COUNT;  //TOTAL_TYPE_COUNT = 3
}
    
public  int  getItemViewType( int  position){
   return  getItem(position).getType();
}
    
public  View getView( int  position, View convertView, ViewGroup parent){
   Item item = getItem(position);
   switch (item.getType()){
     case  TITLE:
       if (convertView ==  null ){
         // 仅创建一个包含title的View
         convertView = inflater.inflate(R.layout.layout_title, parent,  false ); 
         holder=  new  ViewHolder();
         holder.title = convertView.findViewById(R.id.title);
         convertView.setTag(holder);
       else  {
         holder= (ViewHolder)convertView.getTag();
       }
       holder.title.setText(item.title);
     break ;
     // 省略的内容
   }
}

如果模拟header的话就修改TOTAL_TYPE_COUNT = 4,再添加一种type就可以了,而且可以把这个header放到你想要的任何位置。这样就可以跳过那个bug.

你可能感兴趣的:(Android ListView 技巧设置固定可滚动头部)