ScrollView嵌套ListView多种滚动兼容问题的解决

一.ScrollView嵌套ListView,只显示一行问题解决

要让ListView显示完整,需要在ListView的数据源赋值后,获取ListViewItem的数量,既可以得到ListView所需的实际高度,然后重新给ListView分配高度即可。此方案可以完美解决显示一行的问题,而且不需要自定义控件即可实现。

    /*
     * 根据列表项个数动态设置ListView高度,解决ScrollView嵌套ListView只显示一行问题
     */
    private void setListViewHeightByItemCount(ListView listView) {
        ListAdapter  listAdapter =  listView.getAdapter();
        if (listAdapter == null) {
            return;
        }
        int allItemsHeight = 0;
        for (int i = 0; i < listAdapter.getCount(); i++) {
            View listItem = listAdapter.getView(i, null, listView);
            listItem.measure(0, 0);
            //获取所有Items的高度和
            allItemsHeight += listItem.getMeasuredHeight();
        }
        //获取ListView中的所有分割线高度和,如果没有则为0
        int alldevideLineHeight = (listView.getDividerHeight() * (listAdapter.getCount() - 1));
        //给ListView设置高度
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        params.height = allItemsHeight +alldevideLineHeight;
        listView.setLayoutParams(params);
    }

注:如果ListView的数据量很大,需要新起一个线程调用此方法,并用Handler同步,这样可加快页面渲染速度

二.仅保留ScrollView的滚动效果,禁用ListView的滚动

1.在ListView上滑动,也触发父类ScrollView的滑动效果方式

应用场景:下拉ListView缩放父类ScrollView中的顶部图片。

要想让ScrollView滚动,只需要让ScrollView子布局高度超出ScrollView的高度即可。如果内容多,超出父类即可实现了,可如果子类布局的高度不足超出父类的ScrollView,该怎么办?提供一个方案,将ScrollView子布局最底部的控件的android:layout_marginBottom="25dp"属性值,调整到一个恰当大的值,即可让ScrollView触发滚动。ListView的高度可以用第一步中提供的方法解决。

2.在ListView滑动,父类ScrollView不会滚动的方式

这种效果,可以让页面保持单屏,但ListView的滑动效果就被终结了,只能触发ScrollView的滚动事件。实现方式就是重写ListView。

package com.today.ui.view;

import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;

/**
 * 自定义NoScrollListview
 * 
 * @see 防止Listview下滑事件和ScrollView的下滑事件冲突
 */
public class NoScrollListview extends ListView {
    public NoScrollListview(Context context) {
        super(context);
    }

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

    public NoScrollListview(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /**
     * 重设高度
     */
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }

}

三.让被嵌套的ListView滑动到顶端,ScrollView才能滚动

1.自定义ListView,支持滑动到顶部时,ScrollView获取滑动权

这种情况可能出现在下拉刷新中,下拉刷新中的自带的ScrollView嵌套LInearLayout再嵌套一个ListView和其他布局的时候,这时候需要对ListView的高度进行计算。

首先要自定义一个支持下拉刷新的ListView,实现当滑动到顶部时候,滑动权交给父类;当ListView的第一项不在顶部的时候,滑动权在ListView手上。

package com.today.ui.view;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.ListView;

/**
 * 自定义PullRefreshListView
 * @see 防止Listview下滑事件和下拉刷新的下滑事件冲突,重写onInterceptTouchEvent事件
 */
public class PullToRefreshListView extends ListView {

    public PullToRefreshListView(Context context) {
        super(context);
    }

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

    public PullToRefreshListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {

        // 判断是否滑动到顶部了
        if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() == 0) {
            // 滑动到顶部,父类获取到触摸事件,开始下拉刷新;
            getParent().requestDisallowInterceptTouchEvent(false);
        } else {
            // 没有滑动到头部,父类拦截触摸事件,不会触发下拉刷新
            getParent().requestDisallowInterceptTouchEvent(true);
        }
        return super.onInterceptTouchEvent(ev);
    }
}

2.设置ListView的高度为ScrollView的剩余高度

这时候不能通过ListView中的Items数量来设置高度了,而要通过计算下拉刷洗的ScrollView的高度,将此高度设为ListView的高度,这样ListView中的Item数量所需的高度,超过ScrollView的高度的时候,就可以实现ListView滚动,而ScrollView不滚动的效果。

这个需要根据自己嵌套的布局个数计算,展示一个例子:一个下拉刷洗中嵌套了多个控件,计算ListView可以使用的高度

/**
     * 将页面剩余高度设置为ListView的高度
     * 
     * @param listView
     */
    private void setRestHeightToListView(ListView listView) {
        // 下拉刷新控件的高度,即顶级容器高度
        int ptrHeight = mPullRefreshView.getMeasuredHeight();
        // 下拉框高度(嵌套了一个下拉框)
        int spinnerbarHeight = spinner_city.getMeasuredHeight();
        // 标题栏高度(嵌套了一个文本框)
        int deviceBarHeight = deviceBar.getMeasuredHeight();
        // 分割线高度(嵌套了一个View)
        int devideLineHeight = devide_line.getMeasuredHeight();
        // ListView可用的剩余高度,即下拉刷新减去下拉框、分割线、标题栏的高度(实际高度计算)
        int restHeight = ptrHeight - spinnerbarHeight - devideLineHeight - deviceBarHeight;
        // 获取ListView的参数
        ViewGroup.LayoutParams params = listView.getLayoutParams();
        // 组装参数
        params.height = restHeight;
        // 设置ListView的高度
        listView.setLayoutParams(params);
        // ListView代理视图也设置为此高度,即可实现居中显示
        listView.getEmptyView().setLayoutParams(params);
    }

这一步主要是保证,ListView的高度刚好填满ScrollViewListView就可以滚动了。否则ScrollView就会优先滚动,而ListView就会失去了滑动权。所以高度一定要算对,里面的任何一条细线都不要漏掉,只要ScrollView能滚动,而ListView是固定不动的,这就有可能是你的高度算错了,检查下。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值