Android 利用ViewDragHelper实现布局拖拽效果,并检测临界点始终落在左右两边

先贴一个实现的效果图(图片不会变色,应该是转换gif图的时候帧的问题):

使用ViewDragHelper遇到的问题:

  1. 因为需求是一个悬浮窗,悬浮窗布局包裹两个子布局,所以使用ViewDragHelper没法处理跟随滑动(或许是我不知道)
  2. 我做的只要求图片可以滑动,并且不可以滑出屏幕,图片不滑出屏幕有直接能用的方法可以用,但是多了个删除按钮,就需要判断滑到右边屏幕的时候去掉间距和删除按钮的宽度。
  3. 计算悬浮窗滑到水平距离距左边近还是右边,需要让悬浮窗落到相应位置。

跟随滑动具体实现方法

重写onViewPositionChanged方法,实时监听位置发生变化的回调,根据回调得到滑动的距离。然后手动移动删除按钮跟随图片移动。代码如下:

    private void viewFollowChanged( int dx, int dy) {
       mAutoBackView1.offsetTopAndBottom(dy);
       mAutoBackView1.offsetLeftAndRight(dx);
       invalidate();
   }

设置只有按住图片可以滑动

mAutoBackView 表示图片那个view
重写tryCaptureView方法, return child == mAutoBackView;

计算悬浮窗落下位置的关键代码

  if (x < (getMeasuredWidth() / 2f - releasedChild.getMeasuredWidth() / 2f)) {
                   x = 0;
               } else {
                   x = getMeasuredWidth() - releasedChild.getMeasuredWidth()-50;
               }
               Log.e("dbj","x="+x+",y="+y);
               // 移动到指定位置
               mDragger.settleCapturedViewAt( (int) x, (int) y);
               invalidate();

自定义View的全部,可以直接用

public class MyDragView extends RelativeLayout {

    private ViewDragHelper mDragger;

    private View mAutoBackView,mAutoBackView1;

    public MyDragView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            @Override
            public int getViewHorizontalDragRange(View child) {
                //返回可拖动的子视图的水平运动范围(以像素为单位)的大小。
                //对于不能垂直移动的视图,此方法应该返回0。
                return getMeasuredWidth() - child.getMeasuredWidth();
            }

            @Override
            public int getViewVerticalDragRange(View child) {
                //返回可拖动的子视图的竖直运动范围(以像素为单位)的大小。
                //对于不能垂直移动的视图,此方法应该返回0。
                return getMeasuredHeight() - child.getMeasuredHeight();
            }

            @Override
            public boolean tryCaptureView(View child, int pointerId) {
                //返回true表view示捕获当前touch到的
                return  child == mAutoBackView;
            }

            @Override
            public int clampViewPositionHorizontal(View child, int left, int dx) {
                if (left > getWidth() - child.getMeasuredWidth()){
                    //超出左侧边界处理
                    left = getWidth() - child.getMeasuredWidth();
                } else if (left < 0) {
                    //超出右侧边界处理
                    left = 0;
                }
                return left;
            }

            @Override
            public int clampViewPositionVertical(View child, int top, int dy) {
                if (top > getHeight() - child.getMeasuredHeight()){
                    //超出下边界处理
                    top = getHeight() - child.getMeasuredHeight();
                } else if (top < 0) {
                    //超出上边界处理
                    top = 0;
                }
                return top;
            }

            @Override
            public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
                float x = releasedChild.getX();
                float y = releasedChild.getY();
                if (x < (getMeasuredWidth() / 2f - releasedChild.getMeasuredWidth() / 2f)) {
                    x = 0;
                } else {
                    x = getMeasuredWidth() - releasedChild.getMeasuredWidth()-50;
                }
                Log.e("dbj","x="+x+",y="+y);
                // 移动到指定位置
                mDragger.settleCapturedViewAt( (int) x, (int) y);
                invalidate();
                super.onViewReleased(releasedChild, xvel, yvel);
                /**
                 * 贴一个可以贴上下左右四边的代码
                    float x = releasedChild.getX();
                    float y = releasedChild.getY();
                    if (x < (getMeasuredWidth() / 2f - releasedChild.getMeasuredWidth() / 2f)) { // 0-x/2
                        if (x < releasedChild.getMeasuredWidth() / 3f) {
                            x = 0;
                        } else if (y < (releasedChild.getMeasuredHeight() * 3)) { // 0-y/3
                            y = 0;
                        } else if (y > (getMeasuredHeight() - releasedChild.getMeasuredHeight() * 3)) { // 0-(y-y/3)
                            y = getMeasuredHeight() - releasedChild.getMeasuredHeight();
                        } else {
                            x = 0;
                        }
                    } else { // x/2-x
                        if (x > getMeasuredWidth() - releasedChild.getMeasuredWidth() / 3f - releasedChild.getMeasuredWidth()) {
                            x = getMeasuredWidth() - releasedChild.getMeasuredWidth();
                        } else if (y < (releasedChild.getMeasuredHeight() * 3)) { // 0-y/3
                            y = 0;
                        } else if (y > (getMeasuredHeight() - releasedChild.getMeasuredHeight() * 3)) { // 0-(y-y/3)
                            y = getMeasuredHeight() - releasedChild.getMeasuredHeight();
                        } else {
                            x = getMeasuredWidth() - releasedChild.getMeasuredWidth();
                        }
                    }
                    // 移动到x,y
                    mDragger.settleCapturedViewAt((int) x, (int) y);
                    invalidate();
                    super.onViewReleased(releasedChild, xvel, yvel);
**/
            }

            @Override
            public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
                super.onViewPositionChanged(changedView, left, top, dx, dy);
                //位置发生改变时回调
                viewFollowChanged( dx,dy);
            }
        });
    }

    private void viewFollowChanged( int dx, int dy) {
        mAutoBackView1.offsetTopAndBottom(dy);
        mAutoBackView1.offsetLeftAndRight(dx);
        invalidate();
    }
    @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();
        }
    }

    /**
     * onFinishInflate 当View中所有的子控件均被映射成xml后触发
     */
    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mAutoBackView =   getChildAt(0);
        mAutoBackView1=getChildAt(1);
    }

有什么问题,可以在下面评论。

猜你喜欢

转载自blog.csdn.net/TLuffy/article/details/96165199
今日推荐