使用ViewDragHelper 实现吸边效果

    xiaoxiao2021-03-25  64

    由于项目需求需要按钮吸边,就自己动手写了下。对于通过手势拖拽我立马就想到了ViewDragHelper这个系统工具类。有了这个类的存在 我们只需要处理松开手指的逻辑处理和边界控制就行了。 下面是实现代码

    public class SuctionSideView extends RelativeLayout { private final String TAG = "SuctionSideView"; private ViewDragHelper mDragHelper; // 拖拽控制 private View mSuctionView; // 要吸边的view private Point mAutoBackOriginPos = new Point(); // 记录子view现在的位置 private boolean isInit = false; /** * 1 | 2 * ----- * 3 | 4 */ private int centerX;// 屏幕中心的x值 private int centerY;// 屏幕中心的y值 根据这两个属性建立直角坐标系 public SuctionSideView(@NonNull Context context) { super(context,null); } public SuctionSideView(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(); addListener(); } /** * 初始化布局 * @throws Exception */ private void init() { } /** * 监听事件注册 */ private void addListener() { mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return child == mSuctionView; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { final int leftBound = getPaddingLeft() + UIUtil.dp2px(10); final int rightBound = getWidth() - child.getWidth() - leftBound - UIUtil.dp2px(10); final int newLeft = Math.min(Math.max(left, leftBound), rightBound); return newLeft; } @Override public int getViewHorizontalDragRange(View child) { return getMeasuredWidth() - child.getMeasuredWidth(); } @Override public int clampViewPositionVertical(View child, int top, int dy) { final int topBound = getPaddingTop() + UIUtil.dp2px(10); final int bottomBound = getHeight() - child.getHeight() - getPaddingBottom() - UIUtil.dp2px(10); final int newTop = Math.min(Math.max(top,topBound),bottomBound); return newTop; } @Override public int getViewVerticalDragRange(View child) { return getMeasuredHeight() - child.getMeasuredHeight(); } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { if (releasedChild == mSuctionView) { if (releasedChild.getLeft() < centerX) { // 往左移动 moveTo(UIUtil.dp2px(10) + getPaddingLeft(), releasedChild.getTop()); } else { // 往右 moveTo(getWidth() - UIUtil.dp2px(59) - getPaddingRight(), releasedChild.getTop()); } // if (releasedChild.getLeft() < centerX && releasedChild.getTop() < centerY) { // 1象限 // if (releasedChild.getLeft() < releasedChild.getTop()) { // 往左 // moveTo(0, releasedChild.getTop()); // } else { // 网上 // moveTo(releasedChild.getLeft(), 0); // } // } else if (releasedChild.getLeft() > centerX && releasedChild.getTop() < centerY) { // 2象限 // if (getWidth() - releasedChild.getLeft() - getWidth() < getTop() - releasedChild.getHeight()) { // 往右 // moveTo(getWidth() - releasedChild.getWidth() - getPaddingRight(), releasedChild.getTop()); // } else { // 往上 // moveTo(releasedChild.getLeft(), 0); // } // } else if (releasedChild.getLeft() < centerX && releasedChild.getTop() > centerY) { // 3 象限 // if (releasedChild.getLeft() < getHeight() - releasedChild.getTop() - releasedChild.getHeight()) { // 往左 // moveTo(0, releasedChild.getTop()); // } else { // 往下 // moveTo(releasedChild.getLeft(), getHeight() - releasedChild.getHeight() - getPaddingBottom()); // } // } else if (releasedChild.getLeft() > centerX && releasedChild.getTop() > centerY) { // 4象限 // if (getWidth() - releasedChild.getLeft() - releasedChild.getWidth() < getHeight() - releasedChild.getTop() - releasedChild.getHeight()) { // 向右 // moveTo(getWidth() - releasedChild.getWidth() - getPaddingRight(), releasedChild.getTop()); // } else { // 往下 // moveTo(releasedChild.getLeft(), getHeight() - releasedChild.getHeight() - getPaddingBottom()); // } // // } ViewCompat.postInvalidateOnAnimation(SuctionSideView.this); } } }); } private void moveTo(int xvel, int yvel) { mAutoBackOriginPos.x = xvel; mAutoBackOriginPos.y = yvel; mDragHelper.smoothSlideViewTo(mSuctionView,xvel,yvel); } @Override protected void onFinishInflate() { super.onFinishInflate(); mSuctionView = getChildAt(0); LogUtil.i(TAG,"onFinishInflate"); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { centerX = getWidth() / 2; centerY = getHeight() / 2; if (!isInit) { mAutoBackOriginPos.x = getWidth() - UIUtil.dp2px(59); mAutoBackOriginPos.y = getHeight() - UIUtil.dp2px(75); isInit = true; mSuctionView.layout(mAutoBackOriginPos.x,mAutoBackOriginPos.y,mAutoBackOriginPos.x + UIUtil.dp2px(49),mAutoBackOriginPos.y + UIUtil.dp2px(65)); LogUtil.i(TAG,"mAutoBackOriginPos.x:" + mAutoBackOriginPos.x + "mAutoBackOriginPos.y" + mAutoBackOriginPos.y); } } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mDragHelper.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { mDragHelper.processTouchEvent(event); return false; } @Override public void computeScroll() { if (mDragHelper.continueSettling(true)) { invalidate(); } } }

    这里面记录下吸边控件的初始位置。

    clampViewPositionHorizontal与clampViewPositionVertical 这是控制吸边控件的上下左右能够活动位置

    由于我的项目中值需要左右吸边所以我在

    onViewReleased 里只需要判断当前控件的left超过中心线了没

    其中涉及到的数字为吸边控件距左距右和控件本身的尺寸,整个代码差不多100行是不是很简单吧。 使用也非常简单 用自定义好的控件包裹住需要被吸边的控件

    <cn.missfresh.home.widget.SuctionSideView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_below="@+id/title_bar"> <ImageView android:id="@+id/view" android:layout_width="49dp" android:layout_height="65dp" android:layout_gravity="right|bottom" android:layout_marginBottom="10dp" android:layout_marginRight="10dp" android:scaleType="fitXY" android:visibility="gone" /> </cn.missfresh.home.widget.SuctionSideView>
    转载请注明原文地址: https://ju.6miu.com/read-13821.html

    最新回复(0)