可移动自定义viewgroup--viewdraghelp心得

最近项目需要一个可移动的viewgroup控件,这方面还是比较弱的(因为之前都没怎么做这个,而且网上的自定义控件文章很多,看了好久还是没有自信。我想还是没有彻底理解把,唉)在此感谢zhy大神,他的文章总是帮助好多。感谢大神,感谢开源精神。

SlidingPaneLayout和DrawerLayout这两个google的控件不知道大家有没有用过,据说都用到了viewdraghelper。因为我没有看过源码,只是听说。但是这已经说明了它的强大,不是吗?此处有‘赢笑’图片。为什么叫helper类呢,因为android手势处理还是比较复杂的,所以这个帮助类是帮助我们的快速实现的。

  • 创建实例(通过静态工厂方法创建的)
  • 触摸相关的方法的调用
  • ViewDragHelper.Callback实例的编写(大部分方法都在callback里面)
    开始自定义控件

  • 首先当然是继承RelativeLayout(布局viewgroup)

  • ViewDragHelper的初始化
  • ViewDragHelper.Callback
  • 触摸相关的方法的调用
    代码

初始化viewdraghelper

 /**
         * 1.0f传入的值越大,越来越难拉
         */
        mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {

重写callback的方法
此方法决定哪个view可以滑动

/**
             * tryCaptureView如果返回ture则表示可以捕获该view,你可以根据传入的第一个view参数决定哪些可以捕获
             * @param child
             * @param pointerId
             * @return
             */
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mAutoBackView;
//                return true;
            }

设定左右上下滑动的范围

/**
             * 设定左右上下滑动的范围
             * @param child
             * @param left
             * @param dx
             * @return
             */
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                return (getWidth() - mAutoBackView.getWidth())/2;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                int topBound = getPaddingTop();
                int bottomBound = getHeight() - mBottomView.getHeight() - topBound - mAutoBackView.getHeight();
                int newTop = Math.min(Math.max(top,topBound),bottomBound);
                return newTop;
            }

手指释放时调用的方法

/**
             * 手指释放的时候回调
             * @param releasedChild
             * @param xvel
             * @param yvel
             */
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                if (releasedChild == mAutoBackView) {
//                    mAutoBackView.getScrollY()
//                    Log.d("yzj------",""+mAutoBackView.getScrollY());
//                    Log.d("yzj------","mAutoBackOriginPos.x:"+mAutoBackOriginPos.x+"mAutoBackOriginPos.y:"+mAutoBackOriginPos.y);
                    mDragger.settleCapturedViewAt(mAutoBackOriginPos.x, mAutoBackOriginPos.y);
                    invalidate();
                    flag = false;
                }
                super.onViewReleased(releasedChild, xvel, yvel);
            }

当在边缘滑动的时候调用

/**
             * 在边缘滑动的时候调用
             * @param edgeFlags
             * @param pointerId
             */
            @Override
            public void onEdgeTouched(int edgeFlags, int pointerId) {
                super.onEdgeTouched(edgeFlags, pointerId);
            }

view位置改变时调用

/**
             * view位置改变时调用
             * @param changedView
             * @param left
             * @param top
             * @param dx
             * @param dy
             */
            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                super.onViewPositionChanged(changedView, left, top, dx, dy);
                if(top == getHeight() - mBottomView.getHeight() - getPaddingTop() - mAutoBackView.getHeight() && (flag == false)){
                    Log.d("yzj------","move to the most");

                    flag = true;
                }
            }

接下来是触摸相关的方法的调用

@Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        return mDragger.shouldInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mDragger.processTouchEvent(event);
        return true;
    }

layout完成时调用

/**
     * 得到初始化位置
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        mAutoBackOriginPos.x = mAutoBackView.getLeft();
        mAutoBackOriginPos.y = mAutoBackView.getTop();
    }

完成inflate时的调用

@Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mAutoBackView = getChildAt(1);
        mBottomView = getChildAt(2);
    }

通过以上几个方法的调用我相信能帮你实现很多的东西。最后放上全部的代码

public class VDRLayout extends RelativeLayout {
    //helper类
    private ViewDragHelper mDragger;
    //回弹view
    private View mAutoBackView;
    //记录初始位置
    private Point mAutoBackOriginPos = new Point();
    private View mBottomView;
    private boolean flag;

    public VDRLayout(Context context, AttributeSet attrs) {
        this(context, null, 0);
    }

    public VDRLayout(Context context) {
        this(context, null);
    }

    public VDRLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        /**
         * 1.0f传入的值越大,越来越难拉
         */
        mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            /**
             * tryCaptureView如果返回ture则表示可以捕获该view,你可以根据传入的第一个view参数决定哪些可以捕获
             * @param child
             * @param pointerId
             * @return
             */
            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                return child == mAutoBackView;
//                return true;
            }

            /**
             * 设定左右上下滑动的范围
             * @param child
             * @param left
             * @param dx
             * @return
             */
            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                return (getWidth() - mAutoBackView.getWidth())/2;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                int topBound = getPaddingTop();
                int bottomBound = getHeight() - mBottomView.getHeight() - topBound - mAutoBackView.getHeight();
                int newTop = Math.min(Math.max(top,topBound),bottomBound);
                return newTop;
            }

            /**
             * 手指释放的时候回调
             * @param releasedChild
             * @param xvel
             * @param yvel
             */
            @Override
            public void onViewReleased(View releasedChild, float xvel, float yvel) {
                if (releasedChild == mAutoBackView) {
//                    mAutoBackView.getScrollY()
//                    Log.d("yzj------",""+mAutoBackView.getScrollY());
//                    Log.d("yzj------","mAutoBackOriginPos.x:"+mAutoBackOriginPos.x+"mAutoBackOriginPos.y:"+mAutoBackOriginPos.y);
                    mDragger.settleCapturedViewAt(mAutoBackOriginPos.x, mAutoBackOriginPos.y);
                    invalidate();
                    flag = false;
                }
                super.onViewReleased(releasedChild, xvel, yvel);
            }

            /**
             * 在边缘滑动的时候调用
             * @param edgeFlags
             * @param pointerId
             */
            @Override
            public void onEdgeTouched(int edgeFlags, int pointerId) {
                super.onEdgeTouched(edgeFlags, pointerId);
            }

            /**
             * view位置改变时调用
             * @param changedView
             * @param left
             * @param top
             * @param dx
             * @param dy
             */
            @Override
            public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
                super.onViewPositionChanged(changedView, left, top, dx, dy);
                if(top == getHeight() - mBottomView.getHeight() - getPaddingTop() - mAutoBackView.getHeight() && (flag == false)){
                    Log.d("yzj------","move to the most");

                    flag = true;
                }
            }
        });
        //允许哪个边缘可以调用
        mDragger.setEdgeTrackingEnabled(ViewDragHelper.EDGE_BOTTOM);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        //决定我们是否应该拦截当前的事件
        return mDragger.shouldInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //处理事件
        mDragger.processTouchEvent(event);
        return true;
    }

    @Override
    public void computeScroll() {
        if (mDragger.continueSettling(true)) {
            invalidate();
        }
    }

    /**
     * 得到初始化位置
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        mAutoBackOriginPos.x = mAutoBackView.getLeft();
        mAutoBackOriginPos.y = mAutoBackView.getTop();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mAutoBackView = getChildAt(1);
        mBottomView = getChildAt(2);
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值