Detailed usage of Android ViewDragHelper

Keywords: Android github Java xml

1. Introduction

This is a useful class for writing a custom viewgroup ViewDragHelper.It provides a number of useful operations and states to allow listeners to drag and drop and reposition child view s in the parent ViewGroup.

2. Details

1. Steps to use

(1) Customize a View

(2) Create an instance of ViewDragHelper

    dragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
    });

1.0f is that the larger the sensitivity parameter, the more sensitive it is.this is the current ViewGroup, which is the drag processing object of ViewDragHelper and must be ViewGroup.

(3) Calls to touch-related methods

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

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

Give the Tonch event to ViewDragHelper for processing

(4) Implement related methods of ViewDragHelper.CallCack

2. Class introduction

(1) Introduction of common methods of ViewDragHelper

dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_RIGHT | ViewDragHelper.EDGE_BOTTOM);

Set whether the boundary touch callback is activated, by setting the upper, lower, and left boundaries respectively

dragHelper.smoothSlideViewTo(view, getPaddingLeft(), getPaddingTop())

Use animation to smoothly move to specified location, but be sure to add code below

 @Override
 public void computeScroll() {
     if (dragHelper.continueSettling(true)) {
         ViewCompat.postInvalidateOnAnimation(this);
     }
 }

There are other functional methods, such as Cancel, Status Tracking, which are not described here.

(2) Class introduction of ViewDragHelper.Callback, which has been perfected in the sample notes below, is not repeated here.

3. Related Issues

(1) If a child control of ViewGroup consumes a click event, such as a button, the onInterceptTouchEvent method will be used first when touching the screen to determine if it can be captured. In the process of judging, two other callback methods will be used: getViewHorizontalDragRange and getViewVerticalDragRange, which can only be captured properly if they return a value greater than 0.Otherwise, there will be a problem where child controls cannot be dragged.

(2) Add if boundary detection is required

dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_RIGHT | ViewDragHelper.EDGE_BOTTOM);

(3) If the root layout of your current layout is not DragLayout, you may encounter the problem of DragLayout blocking other layout Touch events.At this point, you can consider the onTouchEvent(), onInterceptTouchEvent() method, which dynamically returns true, false, as required.

3. Examples

1. Sample effects

2. Code Analysis

DragLayout.java

import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v4.widget.ViewDragHelper;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;


public class DragLayout extends LinearLayout {
    private static final String TAG = "DragLayout";
    private ViewDragHelper dragHelper;

    private TextView mDragView1;
    private View mDragView2;
    private View mDragView3;

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

    private void init() {
        dragHelper = ViewDragHelper.create(this, callback);

        // Set Boundary Touch Callback Activated
        dragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT | ViewDragHelper.EDGE_TOP | ViewDragHelper.EDGE_RIGHT | ViewDragHelper.EDGE_BOTTOM);
    }

    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {
        /**
         * Specifies whether the View can be dragged
         * @param child User captured view
         * @param pointerId
         * @return Is the captured view draggable
         */
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            return child == mDragView1 || child == mDragView3;
        }

        /**
         * @param state The state of dragging
         *
         * @see # STATE_IDLE Drag End
         * @see # STATE_DRAGGING Dragging
         * @see # STATE_SETTLING Is being placed, this state will not appear
         */
        @Override
        public void onViewDragStateChanged(int state) {
            if (state == ViewDragHelper.STATE_DRAGGING) {
                mDragView1.setText("Dragging");
            } else if (state == ViewDragHelper.STATE_IDLE) {
                mDragView1.setText("Drag End");
            }
        }

        /**
         * Callback when the position of the View changes
         * @param changedView View with current location change
         * @param left view New X-coordinate in upper left corner
         * @param top view New Y-coordinate in upper left corner
         * @param dx Two callbacks to the distance in X-axis direction
         * @param dy Two callbacks to the distance in Y-axis direction
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            Log.d(TAG, "onViewPositionChanged left" + left);
            Log.d(TAG, "onViewPositionChanged top" + top);
            Log.d(TAG, "onViewPositionChanged dx" + dx);
            Log.d(TAG, "onViewPositionChanged dy" + dy);
            Log.d(TAG, "----------------------");
        }

        /**
         * Callback when view is captured
         *
         * @param capturedChild Captured view
         * @param activePointerId
         */
        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {

        }

        /**
         * Callback when finger is released
         * @param releasedChild Released child view
         * @param xvel X-axis speed of finger, leaving screen in pixels per second
         * @param yvel Y-axis speed of finger, leaving screen in pixels per second
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            // Down, right positive, otherwise negative
            if (yvel > 0) {
                if (releasedChild == mDragView3) {
                    smoothToBottom(releasedChild);
                }
                Toast.makeText(getContext(), "When released, the speed goes down greater than 0", Toast.LENGTH_SHORT).show();
            } else if (yvel < 0) {
                if (releasedChild == mDragView3) {
                    smoothToTop(releasedChild);
                }
                Toast.makeText(getContext(), "When released, speed up is greater than 0", Toast.LENGTH_SHORT).show();
            }
        }

        /**
         * Callback when touching parent layout boundary (ViewDragHelper.setEdgeTrackingEnabled must be called to take effect)
         *
         * @param edgeFlags
         * @param pointerId
         */
        @Override
        public void onEdgeTouched(int edgeFlags, int pointerId) {
            if (edgeFlags == ViewDragHelper.EDGE_TOP) {
                Toast.makeText(getContext(), "Upper Boundary", Toast.LENGTH_SHORT).show();
            } else if (edgeFlags == ViewDragHelper.EDGE_BOTTOM) {
                Toast.makeText(getContext(), "To the lower boundary", Toast.LENGTH_SHORT).show();
            } else if (edgeFlags == ViewDragHelper.EDGE_LEFT) {
                Toast.makeText(getContext(), "To the left border", Toast.LENGTH_SHORT).show();
            } else if (edgeFlags == ViewDragHelper.EDGE_RIGHT) {
                Toast.makeText(getContext(), "To the right border", Toast.LENGTH_SHORT).show();
            }
        }

        @Override
        public boolean onEdgeLock(int edgeFlags) {
            return false;
        }

        /**
         * When no child view is captured, drag the child view by touching the boundary (Scene: When the view is out of the screen, you cannot capture the view, you can only roll it back first by touching the screen boundary)
         * @param edgeFlags
         * @param pointerId
         */
        @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
            dragHelper.captureChildView(mDragView2, pointerId);
//            dragHelper.captureChildView(mDragView3, pointerId);
        }

        /**
         * Returns the coordinates of the captured view Z axis (that is, the layer of the current view on the layout)
         * @param index
         * @return
         */
        @Override
        public int getOrderedChildIndex(int index) {
            Log.d(TAG, "getOrderedChildIndex index" + index);
            return index;
        }

        /**
         * Scope that the view drags horizontally (the child control calls back when it consumes a click event (for example, a button))
         * @param child
         * @return
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return getMeasuredWidth() - child.getMeasuredWidth();
        }

        /**
         * The range that the view drags vertically (the child control calls back when it consumes a click event (for example, a button))
         * @param child
         * @return
         */
        @Override
        public int getViewVerticalDragRange(View child) {
            return getMeasuredHeight() - child.getMeasuredHeight();
        }

        /**
         * Limit View's drag range vertically
         * @param child Dragged SubView
         * @param top Coordinates of Y-axis during movement
         * @param dy
         * @return view New Location
         */
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            // Limit the upper and lower boundaries of the view (based on the upper left corner coordinate point of the view)
            final int topBound = getPaddingTop();
            final int bottomBound = getHeight() - child.getHeight();
            final int newTop = Math.min(Math.max(top, topBound), bottomBound);
            return newTop;
        }

        /**
         * Restrict View's drag range horizontally
         * @param child Dragged SubView
         * @param left X-axis coordinates during movement
         * @param dx
         * @return view New Location
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            return left;
        }
    };

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

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

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mDragView1 = (TextView) getChildAt(0);
        mDragView2 = getChildAt(1);
        mDragView3 = getChildAt(2);
    }

    public void smoothToTop(View view) {
        // Animation moves smoothly to the specified position
        if (dragHelper.smoothSlideViewTo(view, getPaddingLeft(), getPaddingTop())) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    public void smoothToBottom(View view) {
        // Animation moves smoothly to the specified position
        if (dragHelper.smoothSlideViewTo(view, getPaddingLeft(), getHeight() - view.getHeight())) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }

    @Override
    public void computeScroll() {
        if (dragHelper.continueSettling(true)) {
            ViewCompat.postInvalidateOnAnimation(this);
        }
    }
}

XML file

<com.wyj.viewdraglayout.DragLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/textview1"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:layout_margin="10dp"
        android:background="#FFDCD665"
        android:gravity="center"
        android:text="Direct-draggable View" />

    <TextView
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_gravity="center"
        android:layout_margin="10dp"
        android:background="#FFDCD665"
        android:gravity="center"
        android:text="Touch borders draggable View" />

    <Button
        android:id="@+id/button"
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:layout_margin="10dp"
        android:background="#FFDCD665"
        android:gravity="center"
        android:text="Button" />


</com.wyj.viewdraglayout.DragLayout>

3. Sample code download

github address https://github.com/Ya-Jun/SmallSampleCollection

Posted by rakennedy75 on Sat, 15 Jun 2019 09:48:55 -0700