欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ListView使用案例一之滑动冲突

程序员文章站 2024-03-24 17:50:16
...

ListView的使用

在我们学会使用recyclerview之前,我们一定是在ListView的世界中在挣扎,彷徨,忧郁,困惑,然而,当我们真正的封装好了的话也可以趟过这趟混水,迈入新的天地。

下面就给大家带来我项目中曾经遇到过的ListView的坑,当然你可能也会遇到,并且有了不一样的处理方法,此处仅供已懂的人参考,不懂的人借鉴。

首先给大家发一波我遇到的各类滑动冲突的‘撞车事故’:

1)ScrollView内部套用ListView,GridView的滚动冲突事件

处理方法:重写ListView的onMeasure()方法即可,代码如下

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

//解决ListView外部套用ScrollView的滚动冲突事件
public class MyListView extends ListView{

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

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

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //设置当前ListVIew的高度为ListView所有内容加起来的整体高度,此高度最多不能超过Integer.MAX_VALUE>>2
        int heightSpec;
        if (getLayoutParams().height==LayoutParams.WRAP_CONTENT){
            heightSpec= MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);
        }else {
            heightSpec=heightMeasureSpec;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }
}

2)解决ScrolView内嵌套ViewPager的滚动问题

处理方法:重写ScrolView的onMeasure()方法即可,代码如下
注:这里可能设计到SimpleOnGestureListener的使用,此为用户触屏时对各类不同手势处理的类,下一篇文章中将做出对它的详细使用说明,当然,如果你是个老司机,也可以直接百度它,也是有一堆合理的解释和使用说明的 -_-)

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.webkit.WebView;
import android.widget.ScrollView;
import android.widget.Scroller;

/**
 * 自定义ScrollView,解决:ScrollView嵌套ViewPager,导致ViewPager不能滑动的问题
 */
public class CustomScrollView extends ScrollView {
    private GestureDetector mGestureDetector;
    private int Scroll_height = 0;
    private int view_height = 0;
    protected Field scrollView_mScroller;
    private static final String TAG = "CustomScrollView";

    public CustomScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new YScrollDetector());
        setFadingEdgeLength(0);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            stopAnim();
        }
        boolean ret = super.onInterceptTouchEvent(ev);
        boolean ret2 = mGestureDetector.onTouchEvent(ev);
        return ret && ret2;
    }

    // Return false if we're scrolling in the x direction
    class YScrollDetector extends SimpleOnGestureListener {
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            if (Math.abs(distanceY) > Math.abs(distanceX)) {
                return true;
            }
            return false;
        }
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        boolean stop = false;
        if (Scroll_height - view_height == t) {
            stop = true;
        }

        if (t == 0 || stop == true) {
            try {
                if (scrollView_mScroller == null) {
                    scrollView_mScroller = getDeclaredField(this, "mScroller");
                }

                Object ob = scrollView_mScroller.get(this);
                if (ob == null || !(ob instanceof Scroller)) {
                    return;
                }
                Scroller sc = (Scroller) ob;
                sc.abortAnimation();

            } catch (Exception e) {
                Log.e(TAG, e.getMessage());
            }
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }

    private void stopAnim() {
        try {
            if (scrollView_mScroller == null) {
                scrollView_mScroller = getDeclaredField(this, "mScroller");
            }

            Object ob = scrollView_mScroller.get(this);
            if (ob == null) {
                return;
            }
            Method method = ob.getClass().getMethod("abortAnimation");
            method.invoke(ob);
        } catch (Exception ex) {
            Log.e(TAG, e.getMessage());
        }
    }

    @Override
    protected int computeVerticalScrollRange() {
        Scroll_height = super.computeVerticalScrollRange();
        return Scroll_height;
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        if (changed == true) {
            view_height = b - t;
        }
    }

    @Override
    public void requestChildFocus(View child, View focused) {
        if (focused != null && focused instanceof WebView) {
            return;
        }
        super.requestChildFocus(child, focused);
    }

    /**
     * 获取一个对象隐藏的属性,并设置属性为public属性允许直接访问
     * 
     * @return {@link Field} 如果无法读取,返回null;返回的Field需要使用者自己缓存,本方法不做缓存
     */
    public static Field getDeclaredField(Object object, String field_name) {
        Class<?> cla = object.getClass();
        Field field = null;
        for (; cla != Object.class; cla = cla.getSuperclass()) {
            try {
                field = cla.getDeclaredField(field_name);
                field.setAccessible(true);
                return field;
            } catch (Exception e) {

            }
        }
        return null;
    }
}

3)ViewPager内部套用ViewPager时发生的横向滑动冲突

处理方法:重写内部横向滑动的ViewPager中的onTouchEvent()方法即可,代码如下
import android.content.Context;
import android.graphics.PointF;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.MotionEvent;

/**
 * 自定义ViewPager,解决ViewPagger嵌套使用时不滑动问题。
 */
public class HorizontalInnerViewPager extends ViewPager {
    /** 触摸时按下的点 **/
    PointF downP = new PointF();
    /** 触摸时当前的点 **/
    PointF curP = new PointF();

    public HorizontalInnerViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new XScrollDetector());
    }
    public HorizontalInnerViewPager(Context context) {
        super(context);

        mGestureDetector = new GestureDetector(context, new XScrollDetector());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);//default
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //每次进行onTouch事件都记录当前的按下的坐标
        curP.x = ev.getX();
        curP.y = ev.getY();

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

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

        return super.onTouchEvent(ev);
    }

}

4)ViewPager中嵌套ScrollView,ScrollView中又嵌套另一个ViewPager的滑动冲突事件

**处理方法:
1)确定嵌套模型:我的嵌套是ViewPager–>ScrollView–>ViewPager;
2)最里面的ViewPager水平滚动时总是会触发最外层的ViewPager滚动,我们用自定义内部的ViewPager即可处理(使用3中相同的处理方法);
3)但此时最里面的ViewPager垂直滚动时外层的ScrollView并不会滚动(增加2中的SimpleOnGestureListener手势滑动监听处理方法)。**
import android.content.Context;
import android.graphics.PointF;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;

/**
 * 自定义ViewPager,解决ViewPagger嵌套使用时不滑动问题。
 */
public class HorizontalInnerViewPager extends ViewPager {
    /** 触摸时按下的点 **/
    PointF downP = new PointF();
    /** 触摸时当前的点 **/
    PointF curP = new PointF();

    /** 自定义手势**/
    private GestureDetector mGestureDetector;

    public HorizontalInnerViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        mGestureDetector = new GestureDetector(context, new XScrollDetector());
    }
    public HorizontalInnerViewPager(Context context) {
        super(context);

        mGestureDetector = new GestureDetector(context, new XScrollDetector());
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return super.onInterceptTouchEvent(ev);//default
        //当拦截触摸事件到达此位置的时候,返回true,
        //说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent
//        return true;
        //接近水平滑动时子控件处理该事件,否则交给父控件处理
//        return mGestureDetector.onTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //每次进行onTouch事件都记录当前的按下的坐标
        curP.x = ev.getX();
        curP.y = ev.getY();

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

        if(ev.getAction() == MotionEvent.ACTION_MOVE){
            float distanceX = curP.x - downP.x;
            float distanceY = curP.y - downP.y;
            //接近水平滑动,ViewPager控件捕获手势,水平滚动
            if(Math.abs(distanceX) > Math.abs(distanceY)){
                //此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰
                getParent().requestDisallowInterceptTouchEvent(true);
            }else{
                //接近垂直滑动,交给父控件处理
                getParent().requestDisallowInterceptTouchEvent(false);
            }
        }

        return super.onTouchEvent(ev);
    }

    private class XScrollDetector extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
//            return super.onScroll(e1, e2, distanceX, distanceY);

            //接近水平滑动时子控件处理该事件,否则交给父控件处理
            return (Math.abs(distanceX) > Math.abs(distanceY));
        }
    }

}

未完待续… …