垂直viewpager 嵌套ScrollView的解决办法

来源:互联网 发布:电影 《人工智能》 编辑:程序博客网 时间:2024/05/22 03:27
最近要做一个这种实现,在网上搜了一圈,据说已解决的办法几乎全试过了,结果就没一个可以的,没办法,只能自己写了,目前我的实现只包含两页fragment,更多页数可以类推。  
       首先实现思想是,外部拦截,即在垂直viewpager的onInterceptTouchEvent事件中对当前页面内scrollview的滑动状态进行判定(false表示触摸事件传递到子view,true表示viewpager自行处理),并确定返回值。
       1、页面处于第一页,scrollview滑动到底部并且触摸事件为向上滑动时 onInterceptTouchEvent 返回true,其他情况返回false
       2、页面出鱼第二页,scrollview滑动到顶部并且触摸事件为向下滑动时 onInterceptTouchEvent 返回true,其他情况返回false
       基于这种思想的实现在实测时,发现viewpager经常会有另一页的小部分显示出来,viewpager加上滑动监听后发现,例如在第一页滑动时,viewpager确实向上滑动了,但是onInterceptTouchEvent 没有返回过true值。具体导致该问题的原因目前还不清楚。为了解决这个问题,我重写了viewpager的scrollTo方法,设置成只有在我设置的viewpager滑动标志位为true时viewpager才调用scrollTo方法,其实就是判断并禁止viewpager滑动。 以下是viewpager和scrollview的代码。
       垂直viewpager的代码:
/** * Created by YU_ZERO on 15/12/28. */public class VerticalViewPager extends ViewPager {    public VerticalViewPager(Context context) {        super(context);        init();    }    public VerticalViewPager(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    private void init() {        // The majority of the magic happens here        setPageTransformer(true, new VerticalPageTransformer());        // The easiest way to get rid of the overscroll drawing that happens on the left and right        setOverScrollMode(OVER_SCROLL_NEVER);    }    private class VerticalPageTransformer implements ViewPager.PageTransformer {        @Override        public void transformPage(View view, float position) {            if (position < -1) { // [-Infinity,-1)                // This page is way off-screen to the left.                view.setAlpha(0);            } else if (position <= 1) { // [-1,1]                view.setAlpha(1);                // Counteract the default slide transition                view.setTranslationX(view.getWidth() * -position);                //set Y position to swipe in from top                float yPosition = position * view.getHeight();                view.setTranslationY(yPosition);            } else { // (1,+Infinity]                // This page is way off-screen to the right.                view.setAlpha(0);            }        }    }    /**     * Swaps the X and Y coordinates of your touch event.     */    private MotionEvent swapXY(MotionEvent ev) {        float width = getWidth();        float height = getHeight();        float newX = (ev.getY() / height) * width;        float newY = (ev.getX() / width) * height;        ev.setLocation(newX, newY);        return ev;    }    //我的代码    //scrollview距离底部的距离    private int diffTop = 100;    //scrollview滑动的距离    private int scrollYBottom = -100;    //是否在向上滑动    private boolean isSlip2Up = true;    //第一页scrollview    public VerticalScrollView topScrollView;    //第二页scrollview    public VerticalScrollView bottomScrollView;    private int mLastX;    private int mLastY;    //滑动至第二页时,第一页子View长度是否变化,如果子页中view长度不会发生变化,可去掉该标志位    private boolean isTopLenChanged = false;    //是否拦截触摸事件    private boolean intercept = false;    @Override    public boolean onInterceptTouchEvent(MotionEvent ev){        super.onInterceptTouchEvent(swapXY(ev));        swapXY(ev);        int  x = (int) ev.getX();        int y = (int) ev.getY();        Activity activity = (Activity) getContext();        if(topScrollView==null || bottomScrollView==null){            topScrollView = (VerticalScrollView) activity.findViewById(R.id.top_scrollview);            bottomScrollView = (VerticalScrollView) activity.findViewById(R.id.bottom_scrollview);        }        diffTop = topScrollView.diff;        scrollYBottom = bottomScrollView.scrollY;        boolean tis2Bottom = diffTop==0? true: false;        boolean bis2Top = scrollYBottom==0? true: false;        intercept = false;        switch (ev.getAction()){            case MotionEvent.ACTION_DOWN:                mLastX = x;                mLastY = y;                isSlip2Up = false;                intercept = false;                break;            case MotionEvent.ACTION_UP:                intercept = false;                isSlip2Up = false;                mLastX = mLastY = 0;                break;            case MotionEvent.ACTION_MOVE:                int deltaX = x - mLastX;                int deltaY = y - mLastY;                if(Math.abs(deltaY)>Math.abs(deltaX)){                    isSlip2Up = deltaY<0? true: false;                }                if(getCurrentItem()==0){                    if(!tis2Bottom){                        isSlip2Up = true;                    }                    if(!isSlip2Up){                        tis2Bottom = false;                    }                    //第一页,当scrollview滑动至底部,手势向上滑动,且该页子view长度没有变化时拦截事件                    intercept = tis2Bottom && isSlip2Up && !isTopLenChanged;                } else if(getCurrentItem()==1){                    //第二页,当scrollview滑动至顶部且手势向下滑动时拦截事件                    intercept = bis2Top && !isSlip2Up;                }                break;            case MotionEvent.ACTION_CANCEL:                intercept = false;                isSlip2Up = false;                mLastX = mLastY = 0;                break;        }        return intercept;    }    public void setIsTopLenChanged(boolean isTopLenChanged) {        this.isTopLenChanged = isTopLenChanged;    }    @Override    public void scrollTo(int x, int y) {        //仅当viewpager滑动标志位为true时,才允许viewpager滑动        if (intercept){            super.scrollTo(x, y);        }    }    @Override    public boolean onTouchEvent(MotionEvent ev) {        return super.onTouchEvent(swapXY(ev));    }}

垂直scrollview:
/** * Created by YU_ZERO on 15/12/28. */public class VerticalScrollView extends ScrollView {    public int diff = 100;    public int scrollY = 0;    public VerticalScrollView(Context context, AttributeSet attrs) {        super(context, attrs);        setFadingEdgeLength(0);    }    @Override    protected void onScrollChanged(int l, int t, int oldl, int oldt) {        diff = getScrollY() + getHeight() - computeVerticalScrollRange();        scrollY = getScrollY();        //以下为当scrollview内子控件高度发生变化时,设置的值,高度如果没有变化,可去掉以下代码        if(getTag()!=null){            if(getTag() instanceof FragmentGoodsDetailsVerticalTop){                ((GoodsDetailsVertical)((FragmentGoodsDetailsVerticalTop) getTag()).getActivity()).getPager().setIsTopLenChanged(false);            } else if(getTag() instanceof FragmentGoodsDetailsVerticalBottom){            }        }        super.onScrollChanged(l, t, oldl, oldt);    }    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        return super.onInterceptTouchEvent(ev);    }}

0 0