ScrollView下,ListView【生存之道】

    xiaoxiao2025-07-17  3

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

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

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

    java代码  /** * 动态设置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(00); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * count); listView.setLayoutParams(params); }

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

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

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

    java代码  @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return false; }

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

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

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

    java代码  /** * 设置不滚动 */ 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的东西

    一. 最初:

    java代码  /** * 虚拟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, nullnull); 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,在这里也可以做到。

    二. 升级:

    java代码  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, nullnull); 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); } }

    这样就可以添加footerView了。最终我是使用了这种方案。

    转载请注明原文地址: https://ju.6miu.com/read-1300784.html
    最新回复(0)