在ScrollView中嵌套ListView

来源:互联网 发布:mac怎么玩steam 编辑:程序博客网 时间:2024/06/05 22:49

零用钱的首页面中使用了这种布局,刚开始会疑惑怎么会有这种奇怪的布局,ScrollView和ListView都是滚动结构,按理来说,这两个控件在UI上可以实现相同的功能,ScrollView中只能放一个控件,通常都是LinearLayout,然后在LinearLayout中添加相应的控件来实现滚动效果。
为什么要使用这么奇怪的布局?
1. ScrollView中只能放一个控件,默认情况下Android是禁止在ScrollView中放入另外的ScrollView的,它的高度是无法计算。
2. ScrollView中嵌套了多个ListView,并且作为整体一起滚动,有了这样的设计需求,于是就有了ScrollView嵌套ListView的奇怪结构。

1. 最简单的布局

如果整个页面只有一个ListView的话,那么由于ListView本身带有滚动效果所以当加载的数据超过页面显示的范围时,可以通过上下滑动来查看所有的item。因此这种情况下,不需要添加ScrollView。

2.布局A+ListView

这种情况下,如果布局A定义在ListView的前面,那么当布局A所占的比例较大,或者ListView加载的数据较多时,都会导致ListView显示不完全。同样,由于ListView自身可以滚动,因此仍然可以通过上下滚动来查看ListView的所有item。
如图所示:

3.其它布局B+ListView

这种情况下,假设布局B定义在ListView的后面,那么就会出现两种情况:
(1)、ListView加载的数据不多,可以完全显示ListView的每一项,那么如果后面还有足够剩余的空间的话,布局B能正常显示;
(2)、ListView加载的数据加多,那么就会导致留给布局B的空间不足,或者根本就没有,布局B将会显示不完全或者完全不显示。


零用钱中则是在滚动布局中添加了三个ListView,我也在代码中尝试过自己在ScrollView中加入ListView,发现ListView的数据加载不全,查了一些资料,对项目中代码有了进一步了解。

设置ListView高度

ListView中的数据是可变的,实际高度需要实际测量。于是需要在代码设置ListView高度的方法。

    public void setListViewHeightBasedOnChildren(ListView listView) {        HomeFragmentAdapter listAdapter = (HomeFragmentAdapter)listView.getAdapter();        if (listAdapter == null) {            return;        }        int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();        for (int i = 0, len = listAdapter.getCount(); i < len; i++) {            // listAdapter.getCount()返回数据项的数目            View listItem = listAdapter.getView(i, null, listView);            if (listItem instanceof ViewGroup) {                listItem.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));            }            listItem.measure(0, 0);  // 计算子项的高度            totalHeight += listItem.getMeasuredHeight();// 统计所有子项的总高度        }        LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)listView.getLayoutParams();        params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));        // listView.getDividerHeight()获取子项间分隔符占用的高度        // params.height最后得到整个ListView完整显示需要的高度        // DANGEROUS , NEVER NEVER NEVER NEVER NEVER NEVER NEVER DELETE THIS !!!!!!!!!!!!!!!!!!!!!!        Toast.makeText(getActivity(), "i am the point " + params.height, Toast.LENGTH_SHORT);        listView.setLayoutParams(params);}

调用方法为:

ListView listView = (ListView) findViewById(id);YourAdapter adapter = new MyAdapter("初始化你的适配器");listView.setAdapter(adapter);setListViewHeightBasedOnChildren(listView);

上面这个方法就是设定ListView的高度了,在为ListView设置了Adapter之后使用,就可以解决问题了。但是这个方法有个细节需要注意:
Adapter中getView方法返回的View的必须由LinearLayout组成,因为只有LinearLayout才有measure()方法,如果使用其他的布局如RelativeLayout,在调用listItem.measure(0, 0);时就会抛异常,因为除LinearLayout外的其他布局的这个方法就是直接抛异常的。
需要手动把ScrollView滚动至最顶端 homeScroll.scrollTo(0, 0);

0 0