Android开发之scrollview嵌套listview相关布局的解析

来源:互联网 发布:a href js 函数 编辑:程序博客网 时间:2024/05/16 08:59

过两天同学要回家相亲结婚去了,昨晚作为送行之聚,喝的是稀里哗啦。早上起来喝了一杯牛奶后却无所事事,所以干脆把前几天做项目时总结的一些知识梳理一下。

其实标题与本文不算太相符,这里借标题引申出一个特殊的布局,进而再去挖掘这种布局的解决思路。这种布局很常见,拿美团首页来说,顶部是一些杂七麻八的布局显示一些分类模块和热门频道之类的,中间是listview,底部是加载更多和其他模块。

这种布局有一个特点就是滑动屏幕可以整体滑动而不是仅仅中间的listview可以滑动,不由得就让人突发奇想——scrollview嵌套listview。好想法,可是真正嵌套的时候却发现listview本来一次性请求有10条数据却显示一条甚至还不完整,并且滑动listview只能在显示一条数据的空间高度上滑动,好别扭吧。造成这种结果的原因是scrollview作为父级滑动控件,listview作为孩子,那么scrollview便会把listview的滑动效果给消费掉,造成listview不知道自身该有多高,也就不能展开了。google一下,android官方也不建议采用类似滑动嵌套滑动的这种奇怪布局。但是需求摆在这里,问题终归要解决。知道了上边的原因问题就好办了。

1.动态计算listview的高度

/*** 动态设置ListView的高度* @param listView*/private void setListViewHeightBasedOnChildren(ListView listView) {    if(listView == null) return;    ListAdapter listAdapter = listView.getAdapter();    if (listAdapter == null) {        return;    }    int totalHeight = 0;    for (int i = 0; i < listAdapter.getCount(); i++) {        View listItem = listAdapter.getView(i, null, listView);        listItem.measure(0, 0);        totalHeight += listItem.getMeasuredHeight();    }    ViewGroup.LayoutParams params = listView.getLayoutParams();    params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));    listView.setLayoutParams(params);}

2.自定义listview重写onMeasure()方法

public class ListViewForScrollView extends ListView {    public ListViewForScrollView(Context context) {        super(context);    }    public ListViewForScrollView(Context context, AttributeSet attrs) {        super(context, attrs);    }    public ListViewForScrollView(Context context, AttributeSet attrs,        int defStyle) {        super(context, attrs, defStyle);    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,        MeasureSpec.AT_MOST);        super.onMeasure(widthMeasureSpec, expandSpec);    }}

方法1和方法2都有一些弊端:

a.显示的时候先显示的是listview的首项,而不是scrollview的顶部,所以视图实例后现将scrollview滑动到顶端。

scrollview = (ScrollView) findViewById(R.id.scrollview);scrollview.smoothScrollTo(0, 0);

b.最令我不能接受的,这样动态计算获取listview的高度,结果是有多少数据listview就显示什么样的高度, 既全部显示,你上下滑动的时候listview的重用机制就失效了,数据量大的话内存会一个劲的往上涨,这样做是不合理的。当然数据量少的话是可以采用的,尤其是方法2,由listview重写onMeasure一口气测量,速度更快。

c.第一种方法的item必须是LinearLayout,是利用LinearLayout的measure()方法来测量的。

3.自定义LinearLayout来取代listview

既然scrollview里嵌套listveiw的这种滑动嵌套滑动容易出现问题,我们何不用LinearLayout来取代listview。Linearlayout有一个addvie()方法,可以将每一个item添加进去形成LinearLayout的子项,这样我们不需要计算高度的问题了。但是同样有一个问题,还是不能重用。

4.为listview设定一个高度。

遇到数据量大的情况,我们事先已经知道,那么干脆初步给listview预设一个高度,然后在嵌套在scrollview中,这样既能重用数据,又能整体滑动,也不失为一种解决方法。

5.整体只用listview一个滑动控件

以上三种都是用scrollview嵌套listview。换种思维,我们知道listview里面有addHeaderView(),addFooterView(),addView()。可以利用三个方法在合适的时候将相应部分的数据添加进去,另外listview的所有属性都可以使用,包括重用机制。个人推荐。


0 0
原创粉丝点击