现在许多应用中都有用到listview和viewpager共存的界面,像知乎日报这样
当下方的listview滚动时,上面的图片也会跟着滚动,简单的来说就是在listview中嵌套一个viewpager,并且将viewpager放在第一个item里面。
容易遇到的问题
自己第一次尝试写这种界面的时候变遇到了一个bug,在我多次对listview进行上下滚动之后(让viewpager出现,再消失,再出现,循环),viewpager的切换出现卡顿,甚至不响应切换的动作,系统也没有报错,但这样是远远不能拿来实用的。
问题分析
Listview的中的第一行viewpager因为多次每一次都出现需要重新生成导入,内存不足,而导致出现卡顿的现象。
解决这问题,需要了解listview的原理,网上有张图很能说明问题
(图为网上查找)
从图中可以看出,listview保持了一个回收器,不可见的视图会被放在回收器里面,并不会直接销毁,当另一个不可见的视图变成可见的时候,便会从回收期里将视图导出,再次使用。像图中的例子,整个列表的显示过程中,我们只需要同时维持7个listitem便可以了,即使有成千上万个需要显示。对listview的性能优化也是依据的这个。(listview的优化是充分利用回收机制,和灵活的Holder的使用,这个网上很多,就不细说了)
原理图中只使用了一种视图,如果在一个列表中包含多种不同视图怎么办。其实这也是解决我这次问题的关键,在Recycler中对回收的视图都是有按照Type存储的,在重写的ListView的适配器中,我们可以重写一个方法,getViewTypeCount(),用它来设置Recycler中的Type数量。然后再重写getItemViewType(int position)来为每个position位置上的item设置自己的视图type。然后再让我们来走一下滚动时,视图转换流程,向上滚动时消失的视图将按照type存储在Recycler的相应位置,然后下方刚出现的item8的convertView便是根据item8的type在Recycler取出的。这样就能通过按照type区分,实现多种视图共同缓存。
解决方法
将第一行的viewpager和下面的listitem都通过Recycler实现缓存,这样对于viewpager,不是造成每一次都需要重新穿建。
核心代码主要是在ListView的重新写的适配器中
package com.example.listviewtest;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class MyListAdapter extends BaseAdapter{
private static final int TYPE_LISTVIEW = 0;
private static final int TYPE_VIEWPAGER = 1;
private static final int TYPE_COUNT = 2;
private Context mContext;
private List<String> list;
private View viewPager;
public MyListAdapter(Context mContext, List<String> list) {
super();
this.mContext = mContext;
this.list=list;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size()+1;
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
if (position==0) {
return viewPager;
} else {
return list.get(position-1);
}
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
Holder holder = null;
switch(getItemViewType(position)){
case TYPE_LISTVIEW:
if(convertView==null){
holder = new Holder();
convertView=LayoutInflater.from(mContext)
.inflate(R.layout.list_item, null);
holder.tv=(TextView)convertView.findViewById(R.id.tv);
convertView.setTag(holder);
}else{
holder = (Holder) convertView.getTag();
}
break;
case TYPE_VIEWPAGER:
if(convertView==null){
convertView=viewPager;
}
return convertView;
}
if(viewPager!=null){
position--;
}
holder.tv.setText(list.get(position));
return convertView;
}
public void setViewPager(View view) {
// TODO Auto-generated method stub
viewPager=view;
}
@Override
public int getItemViewType(int position) {
// TODO Auto-generated method stub
if(viewPager!=null){
return position > 0 ? TYPE_LISTVIEW : TYPE_VIEWPAGER;
}else{
return TYPE_LISTVIEW;
}
}
@Override
public int getViewTypeCount() {
// TODO Auto-generated method stub
return TYPE_COUNT;
}
public class Holder {
public TextView tv;
}
}
按照这样的修改之后,实现的下图所示的效果,运行起来超级流畅,bug问题完美解决掉了
Demo下载地址http://download.csdn.net/detail/u012568402/8194703点击打开链接
希望读者能有所收获