ScrollView嵌套ListView

来源:互联网 发布:北京软件开发学校 编辑:程序博客网 时间:2024/06/05 02:20

ScrollView控件只能盛放一个直接子控件(通常情况下盛放一个线性布局LinearLayout,且orientation属性为vertical。若ListView在布局中时,ListView的高度设为适应自身内容(wrap_content),却只显示了1条数据。

究其原因,就是ScrollView滑动事件与ListView滑动事件相互冲突,ListView不能正确地计算高度所致。对于这个问题,通常有两个比较合适的解决方案,先分享如下。

解决方案(一):动态设置ListView高度

在.xml布局文件中直接指定ListView的高度,但是ListView中的数据是可变的,其实际高度还需要实际测量。于是我们可以动态地设置ListView的高度。

/**
* 动态地设置ListView的高度
* @param listView
*/
public static void setListViewHeightBasedOnItems(ListView listView) {
    if(listView == null) {
        return;
    }
        
    ListAdapter listAdapter = listView.getAdapter();
    if (listAdapter == null) {
        // pre-condition
        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);
}

我们在进行项目开发中,可以采用上述方法,将目标ListView以参数的形式传递进去。需要注意的是,该方法的调用要在.setAdapter()方法调用之后。

在实际项目中发现,如果在控件初始化的时候调用改方法,当ListView中的Adapter中的数据源发生变化的时候,单纯地采用.notifyDataSetChanged()方法,结果显示的还是一行item的高度。

所以,该方法不是不是最为稳妥的解决方式。那么,为了更好地解决这个问题,可以采用下面的解决方案。

解决方案(二):自定义ListView,重写onMeasure()方法

public class CustomListView extends ListView{
    public CustomListView(Context context) {
        super(context);
    }

    public CustomListView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public CustomListView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}

该方法自定义了一个ListView,并重写onMeasure()方法。默认显示两项,当更多数据时,会显示实际的item数量。项目开发中,可以在布局文件中引入自定义的ListView,剩下的操作跟原生的ListView用法一致。

特别说明一点,在首次动态加载Listview的items后页面会跳转到ListView的第一个子项,对此可以采用下面的解决方式:

mScrollView.post(
    new Runnable(){
        mScrollView.scrollTo(0,0);
    }
);

该方法将会强制跳转到ScrollView的顶部位置。





原创粉丝点击