ScrollView与listView,GridView,Viewpager的冲突及解决方法!!!

ScrollView是带有滚动事件的控件,与listView和GridView以及Viewpager嵌套使用时经常会出现很多问题。例如listView和GridView只能在ScrollView显示一行等。所以Google是不推荐我们去做ScrollView内嵌操作的,但是有的时候,需求需要~我们不得不这么使用。所以接下来我给大家讲一些基础的解决冲突的办法。

1.ScrollView嵌套ListView,有2种方法解决

1.1自定义View
public class ScrollListView extends ListView {
    public ScrollListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public ScrollListView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}
1.2动态测量Listview的高度
/**
 * 动态控制listView的高度
 */
public static void setListViewHeightBasedOnChildren(ListView listView) {
    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.ScrollView嵌套GridView,有2种方法解决---与ListView类似

2.1自定义View
public class ScrollGridView extends GridView {
    public ScrollGridView(Context context, AttributeSet attrs) {
        super(context, attrs);
        // TODO Auto-generated constructor stub
    }

    public ScrollGridView(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }


    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // TODO Auto-generated method stub
        int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
                MeasureSpec.AT_MOST);
        super.onMeasure(widthMeasureSpec, expandSpec);
    }
}
2.2动态测量Gridview的高度
/**
 * 动态控制gridview的高度
 */
public static void setGridViewHeightBasedOnChildren(GridView gridView, int number) {
    //获取listview的适配器
    ListAdapter listAdapter = gridView.getAdapter();
    int numCollumn = number;
    //item的高度
    if (listAdapter == null) {
        return;
    }
    int totalHeight = 0;
    for (int i = 0; i < listAdapter.getCount(); i++) {
        if (i % numCollumn == 0) {
            View listItem = listAdapter.getView(i, null, gridView);
            listItem.measure(0, 0);
            totalHeight += listItem.getMeasuredHeight();
        }
    }
    ViewGroup.LayoutParams params = gridView.getLayoutParams();
    params.height = totalHeight;
    gridView.setLayoutParams(params);
}

3.ScrollView嵌套ViewPager,有2种方法解决

3.1自定义ScrollView
/** 
  * 能够兼容ViewPager的ScrollView 
  *  
  * @Description: 解决了ViewPager在ScrollView中的滑动反弹问题 
  */  
public class ScrollViewExtend extends ScrollView {  
    // 滑动距离及坐标  
    private float xDistance, yDistance, xLast, yLast;  
  
    public ScrollViewExtend(Context context, AttributeSet attrs) {  
        super(context, attrs);  
    }  
  
    @Override  
    public boolean onInterceptTouchEvent(MotionEvent ev) {  
        switch (ev.getAction()) {  
        case MotionEvent.ACTION_DOWN:  
            xDistance = yDistance = 0f;  
            xLast = ev.getX();  
            yLast = ev.getY();  
            break;  
        case MotionEvent.ACTION_MOVE:  
            final float curX = ev.getX();  
            final float curY = ev.getY();  
  
            xDistance += Math.abs(curX - xLast);  
            yDistance += Math.abs(curY - yLast);  
            xLast = curX;  
            yLast = curY;  
  
            if (xDistance > yDistance) {  
                return false;  
            }  
        }  
        return super.onInterceptTouchEvent(ev);  
    }  
}  
3.2自定义viewPager
public class MyViewPager extends ViewPager {
    /**
     * 触摸时按下的点
     **/
    PointF downP = new PointF();
    /**
     * 触摸时当前的点
     **/
    PointF curP = new PointF();
    OnSingleTouchListener onSingleTouchListener;

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

    public MyViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    @Override
    public boolean onTouchEvent(MotionEvent arg0) {
        // 每次进行onTouch事件都记录当前的按下的坐标
        curP.x = arg0.getX();
        curP.y = arg0.getY();

        if (arg0.getAction() == MotionEvent.ACTION_DOWN) {
            // 记录按下时候的坐标
            // 切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变
            downP.x = arg0.getX();
            downP.y = arg0.getY();
            // 此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
            getParent().requestDisallowInterceptTouchEvent(true);
        }

        if (arg0.getAction() == MotionEvent.ACTION_MOVE) {
            // 此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
            getParent().requestDisallowInterceptTouchEvent(true);
        }

        if (arg0.getAction() == MotionEvent.ACTION_UP) {
            // 在up时判断是否按下和松手的坐标为一个点
            // 如果是一个点,将执行点击事件,这是我自己写的点击事件,而不是onclick
            if (downP.x == curP.x && downP.y == curP.y) {
                onSingleTouch();
                return true;
            }
        }

        return super.onTouchEvent(arg0);
    }
    /**
     * 单击
     */
    public void onSingleTouch() {
        if (onSingleTouchListener != null) {

            onSingleTouchListener.onSingleTouch();
        }
    }

    /**
     * 创建点击事件接口
     */
    public interface OnSingleTouchListener {
        public void onSingleTouch();
    }

    public void setOnSingleTouchListener(
            OnSingleTouchListener onSingleTouchListener) {
        this.onSingleTouchListener = onSingleTouchListener;
    }
}

4.若嵌套的ListView和GridView的高度超出了ScrollView,那么ScrollView会自动滑到底部。

那么我们只需要使用一个顶部控件主动获取焦点便能解决这个问题。解决代码如下。

    view.setFocusable(true);  
    view.setFocusableInTouchMode(true);  
    view.requestFocus();  

备注:自定义ListView的详细介绍 传送门

你可能感兴趣的:(ScrollView与listView,GridView,Viewpager的冲突及解决方法!!!)