您的位置:首页 > 其它

ScrollView下,ListView重复调用getview解决方案

2016-05-03 11:10 337 查看
首先讲一下我遇到的需求吧,页面是这样的,上边有东西,中间是列表,下边还有东西。首先我看到列表立刻就想到了用ListView,但是页面有限,只能用ScrollView包一下。想到就做呗。我就在ScrollView里面加了一个ListView, ListView设置的是wapcontent,这样就出现了ListView数据只显示出了一行。好的,解决问题的方案就来了。

一.设置scrollView中的ListView内容全部显示,不能滑动,将滑动交给scrollView去做。

做法:在设置adapter之前,重新计算ListView的高度,我这里写了一个方法:

[html] view
plain copy

 





/**  

* 动态设置listView的高度  

* count 总条目  

*/  

private void setListViewHeight(ListView listView, BaseAdapter adapter,  

int count) {  

int totalHeight = 0;  

for (int i = 0; i < count; i++) {  

View listItem = adapter.getView(i, null, listView);  

listItem.measure(0, 0);  

totalHeight += listItem.getMeasuredHeight();  

}  

ViewGroup.LayoutParams params = listView.getLayoutParams();  

params.height = totalHeight + (listView.getDividerHeight() * count);  

listView.setLayoutParams(params);  

}  

这样做的前提条件是布局文件中ListView的高度要指定,这样才能重新计算,不要设成wapcontent!

二.不全部展示数据,二者皆可滑动。

此方法不用重新计算ListView的高度,只需焦点在Listview上的时候,ScrollView能把滑动权主动交给Listview,这样需要重写ScrollView的一个方法,如下:

[html] view
plain copy

 





@Override  

public boolean onInterceptTouchEvent(MotionEvent ev) {  

return false;  

}  

这样Scrollview就会根据焦点而让出滑动事件。

三.  不重新计算ListView的高度,展示所有数据,ListView不可滑动。

这个做法是重写ListView的onMeasure方法,如下:

[html] view
plain copy

 





/**  

* 设置不滚动  

*/  

public void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  

{  

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,  

MeasureSpec.AT_MOST);  

super.onMeasure(widthMeasureSpec, expandSpec);  

}  

这种方法是同事告诉我的,我没有用过。

做到这里,ScrollView和ListView的问题是解决了,但是ListView的效率问题出现了。

你会发现在ListView的adapter里的getview方法重复执行了很多次,技术使用了缓存技术也是无用的。

有时候数据只有两三个,但是getView方法却被执行了40多次。这样肯定是不行的。但是为什么单独使用ListView的时候却不会出现这种问题呢?

这个原因肯定出在ScrollView和ListView共存上。Google了一下,外国人都不建议他们共存,但是需求是这样的怎么办呢?

我的最终解决方案:自己写一个类似ListView的东西
一. 最初:

[html] view
plain copy

 





/**  

* 虚拟listview  

*  

* @author JustMe  

*  

*/  

public class MyListView extends LinearLayout {  

private BaseAdapter adapter;  

private MyOnItemClickListener onItemClickListener;  

/**  

* 通知更新listview  

*/  

public void notifyChange() {  

int count = getChildCount();  

LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT,  

LayoutParams.WRAP_CONTENT);  

for (int i = count; i < adapter.getCount(); i++) {  

final int index = i;  

final LinearLayout layout = new LinearLayout(getContext());  

layout.setLayoutParams(params);  

layout.setOrientation(VERTICAL);  

View v = adapter.getView(i, null, null);  

v.setOnClickListener(new OnClickListener() {  

@Override  

public void onClick(View v) {  

if (onItemClickListener != null) {  

onItemClickListener.onItemClick(MyListView.this,  

layout, index, adapter.getItem(index));  

}  

}  

});  

// 每个条目下面的线  

ImageView imageView = new ImageView(getContext());  

imageView.setBackgroundResource(R.drawable.divider_list);  

imageView.setLayoutParams(params);  

layout.addView(v);  

layout.addView(imageView);  

addView(layout, index);  

}  

}  

public MyListView(Context context) {  

super(context);  

initAttr(null);  

}  

public MyListView(Context context, AttributeSet attrs) {  

super(context, attrs);  

initAttr(attrs);  

}  

/**  

* 设置方向  

*  

* @param attrs  

*/  

public void initAttr(AttributeSet attrs) {  

setOrientation(VERTICAL);  

}  

public BaseAdapter getAdapter() {  

return adapter;  

}  

/**  

* 设置adapter并模拟listview添加数据  

*  

* @param adpater  

*/  

public void setAdapter(BaseAdapter adpater) {  

this.adapter = adpater;  

notifyChange();  

}  

/**  

* 设置条目监听事件  

*  

* @param onClickListener  

*/  

public void setOnItemClickListener(MyOnItemClickListener onClickListener) {  

this.onItemClickListener = onClickListener;  

}  

/**  

* 点击事件监听  

*  

* @author JustMe  

*  

*/  

public static interface MyOnItemClickListener {  

public void onItemClick(ViewGroup parent, View view, int position,  

Object o);  

}  

}  

这样实现了ListView的最基本的功能,并且提高了效率,例如,全选功能比以上那些方法的速度提高了2-3秒,页面也不卡顿。

缺点是不能一次加载很多的数据,不然数据会显示的很慢,最好分页加载。说到分页,之前都是在ListView上加footerView,在这里也可以做到。

二. 升级:

[html] view
plain copy

 





public class MyListView extends LinearLayout{  

private BaseAdapter adapter;  

private MyOnItemClickListener onItemClickListener;  

boolean footerViewAttached = false;  

private View footerview;  

/**  

* 通知更新listview  

*/  

public void notifyChange() {  

int count = getChildCount();  

if (footerViewAttached) {  

count--;  

}  

LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT);  

for (int i = count; i < adapter.getCount(); i++) {  

final int index = i;  

final LinearLayout layout = new LinearLayout(getContext());  

layout.setLayoutParams(params);  

layout.setOrientation(VERTICAL);  

View v = adapter.getView(i, null, null);  

v.setOnClickListener(new OnClickListener() {  

@Override  

public void onClick(View v) {  

if (onItemClickListener != null) {  

onItemClickListener.onItemClick(MyListView.this, layout, index,  

adapter.getItem(index));  

}  

}  

});  

ImageView imageView = new ImageView(getContext());  

imageView.setBackgroundResource(R.drawable.divider_list);  

imageView.setLayoutParams(params);  

layout.addView(v);  

layout.addView(imageView);  

addView(layout, index);  

}  

}  

public MyListView(Context context) {  

super(context);  

initAttr(null);  

}  

public MyListView(Context context, AttributeSet attrs) {  

super(context, attrs);  

initAttr(attrs);  

}  

public void initAttr(AttributeSet attrs) {  

setOrientation(VERTICAL);  

}  

/**  

* 初始化footerview  

*  

* @param footerView  

*/  

public void initFooterView(final View footerView) {  

this.footerview = footerView;  

}  

/**  

* 设置footerView监听事件  

*  

* @param onClickListener  

*/  

public void setFooterViewListener(OnClickListener onClickListener) {  

this.footerview.setOnClickListener(onClickListener);  

}  

public BaseAdapter getAdapter() {  

return adapter;  

}  

/**  

* 设置adapter并模拟listview添加????数据  

*  

* @param adpater  

*/  

public void setAdapter(BaseAdapter adpater) {  

this.adapter = adpater;  

removeAllViews();  

if (footerViewAttached)  

addView(footerview);  

notifyChange();  

}  

/**  

* 设置条目监听事件  

*  

* @param onClickListener  

*/  

public void setOnItemClickListener(MyOnItemClickListener onClickListener) {  

this.onItemClickListener = onClickListener;  

}  

/**  

* 没有下一页了  

*/  

public void noMorePages() {  

if (footerview != null && footerViewAttached) {  

removeView(footerview);  

footerViewAttached = false;  

}  

}  

/**  

* 可能还有下一??  

*/  

public void mayHaveMorePages() {  

if (!footerViewAttached && footerview != null) {  

addView(footerview);  

footerViewAttached = true;  

}  

}  

public static interface MyOnItemClickListener {  

public void onItemClick(ViewGroup parent, View view, int position, Object o);  

}  

}  

个人测试结果:非常好用

使用方法:跟listview使用一样,只是刷新方法不同,首先刷新adater数据源,再重新设置下其adapter。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: