ViewDragHelper, viewdraghelper

Source: Internet
Author: User

ViewDragHelper, viewdraghelper

   At the Google I/o conference in 2013, we introduced two new layout: SlidingPaneLayout and DrawerLayout. These two classes are now widely used, in fact, if you study their source code, you will find that both classes use ViewDragHelper to process the drag.ViewDragHelper is an unknown but useful tool in the framework..

ViewDragHelper solves the problem of overly complicated gesture processing in android. Before DrawerLayout appeared, the slide menu was implemented by a third-party open source code. Among them, the famous menu is MenuDrawer, menuDrawer overrides the onTouchEvent method to achieve the side slide effect. The Code volume is large, and the Implementation logic also requires a lot of patience to understand. If every developer starts from such an original step, it is quite unfavorable to the Android ecosystem. So the appearance of ViewDragHelper reflects that the android development framework has begun to mature.

This article first introduces the basic usage of ViewDragHelper, and then introduces an example that can truly reflect the practicality of ViewDragHelper.

In fact, ViewDragHelper is not the first class used to analyze gesture processing. gesturedetector is also the first class, but gesturedetector can only say that it is difficult to analyze gestures related to dragging.

ViewDragHelper has the following points:

ViewDragHelper. Callback is the bridge between ViewDragHelper and view (this view generally refers to the container with sub-view, that is, parentView );

ViewDragHelper instances are created using the static factory method;

You can specify the direction of the drag;

ViewDragHelper can detect whether the edge is reached;

ViewDragHelper does not directly act on the View to be dragged, but enables the Sub-View in the view container controlled by ViewDragHelper to be dragged. If you want to specify the behavior of a sub-View, you need to find a solution in Callback;

ViewDragHelper is actually an analysisonInterceptTouchEventAndOnTouchEventMotionEventParameters, and then according to the analysis results to change the position of the dragged sub-View in a container (throughOffsetTopAndBottom (int offset) and offsetLeftAndRight (int offset)Method), which can be used to determine the Child View that is being dragged during touch;

AlthoughViewDragHelperViewDragHelper create (ViewGroup forParent, Callback cb) can specifyViewDragHelperThe object that handles the drag event,ViewDragHelperThe design of the Class determines its applicability to be included in a custom ViewGroup, rather than the use of view containers on any layout.ViewDragHelper.

-----------------------------------------------------------------------------------------------

This article first posted on my personal website http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0911/1680.html

-----------------------------------------------------------------------------------------------------

Usage:

1.ViewDragHelperInitialization

ViewDragHelperIt is generally used within a custom ViewGroup. For example, the following defines a DragLayout inherited from LinearLayout. Inside DragLayout, A viewmDragView is used as a member variable:

public class DragLayout extends LinearLayout {private final ViewDragHelper mDragHelper;private View mDragView;public DragLayout(Context context) {  this(context, null);}public DragLayout(Context context, AttributeSet attrs) {  this(context, attrs, 0);}public DragLayout(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);}

Create a callback ViewDragHelper

 

public DragLayout(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);  mDragHelper = ViewDragHelper.create(this, 1.0f, new DragHelperCallback());}

1.0f is the greater the sensitivity parameter, the more sensitive it is. The first parameter is this, which indicates the object generated by this class. It isViewDragHelperMust be ViewGroup.

To makeViewDragHelperTo be able to process the drag, you need to pass the touch eventViewDragHelper, AndgesturedetectorIs the same:

@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {  final int action = MotionEventCompat.getActionMasked(ev);  if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {      mDragHelper.cancel();      return false;  }  return mDragHelper.shouldInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {  mDragHelper.processTouchEvent(ev);  return true;}

Next, you can process various drag actions in the callback.


2. Processing of dragging Behavior

Process horizontal dragging:

InDragHelperCallbackImplementNow the clampViewPositionHorizontal method, and return an appropriate value to achieve the horizontal drag effect, the second clampViewPositionHorizontalA parameter is the x coordinate that should be reached by dragging the child view. Therefore, according to common sense, this method can return the second parameter in the original form. However, in order to prevent the dragged view from being dragged when it encounters a boundary, the returned value is considered more.

@Overridepublic int clampViewPositionHorizontal(View child, int left, int dx) {  Log.d("DragLayout", "clampViewPositionHorizontal " + left + "," + dx);  final int leftBound = getPaddingLeft();  final int rightBound = getWidth() - mDragView.getWidth();  final int newLeft = Math.min(Math.max(left, leftBound), rightBound);  return newLeft;}

Same as above, handling vertical drag:

InDragHelperCallbackImplementationclampViewPositionVerticaL method, the implementation process is the same as clampViewPositionHorizontal

@Overridepublic int clampViewPositionVertical(View child, int top, int dy) {  final int topBound = getPaddingTop();  final int bottomBound = getHeight() - mDragView.getHeight();  final int newTop = Math.min(Math.max(top, topBound), bottomBound);  return newTop;}

ClampViewPositionHorizontal andclampViewPositionVerticaL it must be rewritten because it returns 0 by default. In fact, what we can do in these two methods is very limited. I personally think the role of these two methods is to give us the opportunity to redefine the target coordinates.

PassDragHelperCallbackThe Return Value of the tryCaptureView method of can determine which sub-view in a parentview can be dragged. Now we assume there are two sub-views (mDragView1 and mDragView2). After tryCaptureView is implemented as follows, only mDragView1 can be dragged.

1234 @Overridepublic boolean tryCaptureView(View child, int pointerId) {  returnchild == mDragView1;}

Sliding edge:

It can be divided into sliding left edge or right edge: EDGE_LEFT and EDGE_RIGHT. The following Code sets the sliding left edge to be processed:

mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);

If the above settings are used, the onEdgeTouched method will be called when the left edge slides. In this case, it is generally not in contact with the child view.

@Overridepublic void onEdgeTouched(int edgeFlags, int pointerId) {    super.onEdgeTouched(edgeFlags, pointerId);    Toast.makeText(getContext(), "edgeTouched", Toast.LENGTH_SHORT).show();}

If you want to move a sub-view based on the sliding distance when sliding the edge, you can implement the onEdgeDragStarted method and manually specify the sub-View to be moved in the onEdgeDragStarted method.

@Overridepublic void onEdgeDragStarted(int edgeFlags, int pointerId) {    mDragHelper.captureChildView(mDragView2, pointerId);}

ViewDragHelper makes it easy for us to implement a control similar to the YouTube video browsing effect. The effect is as follows:


Key points in the Code:

1. tryCaptureView returns the unique header view that can be dragged;

2. The calculation of the drag range is completed in onLayout;

3. Note the ViewDragHelper methods used in onInterceptTouchEvent and onTouchEvent;

4. Use the continueSettling method in computeScroll (because ViewDragHelper uses scroroller)

5. The smoothSlideViewTo method is used to complete the inertia operation after the drag is completed.

It should be noted that the Code still has a lot of room for improvement.

Activity_main.xml

<FrameLayout        xmlns:android="http://schemas.android.com/apk/res/android"        android:layout_width="match_parent"        android:layout_height="match_parent">    <ListView            android:id="@+id/listView"            android:layout_width="match_parent"            android:layout_height="match_parent"            android:tag="list"            />    <com.example.vdh.YoutubeLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:id="@+id/youtubeLayout"            android:orientation="vertical"            android:visibility="visible">        <TextView                android:id="@+id/viewHeader"                android:layout_width="match_parent"                android:layout_height="128dp"                android:fontFamily="sans-serif-thin"                android:textSize="25sp"                android:tag="text"                android:gravity="center"                android:textColor="@android:color/white"                android:background="#AD78CC"/>        <TextView                android:id="@+id/viewDesc"                android:tag="desc"                android:textSize="35sp"                android:gravity="center"                android:text="Loreum Loreum"                android:textColor="@android:color/white"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:background="#FF00FF"/>    </com.example.vdh.YoutubeLayout></FrameLayout>

YoutubeLayout. java
public class YoutubeLayout extends ViewGroup {private final ViewDragHelper mDragHelper;private View mHeaderView;private View mDescView;private float mInitialMotionX;private float mInitialMotionY;private int mDragRange;private int mTop;private float mDragOffset;public YoutubeLayout(Context context) {  this(context, null);}public YoutubeLayout(Context context, AttributeSet attrs) {  this(context, attrs, 0);}@Overrideprotected void onFinishInflate() {    mHeaderView = findViewById(R.id.viewHeader);    mDescView = findViewById(R.id.viewDesc);}public YoutubeLayout(Context context, AttributeSet attrs, int defStyle) {  super(context, attrs, defStyle);  mDragHelper = ViewDragHelper.create(this, 1f, new DragHelperCallback());}public void maximize() {    smoothSlideTo(0f);}boolean smoothSlideTo(float slideOffset) {    final int topBound = getPaddingTop();    int y = (int) (topBound + slideOffset * mDragRange);    if (mDragHelper.smoothSlideViewTo(mHeaderView, mHeaderView.getLeft(), y)) {        ViewCompat.postInvalidateOnAnimation(this);        return true;    }    return false;}private class DragHelperCallback extends ViewDragHelper.Callback {  @Override  public boolean tryCaptureView(View child, int pointerId) {        return child == mHeaderView;  }    @Override  public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {      mTop = top;      mDragOffset = (float) top / mDragRange;        mHeaderView.setPivotX(mHeaderView.getWidth());        mHeaderView.setPivotY(mHeaderView.getHeight());        mHeaderView.setScaleX(1 - mDragOffset / 2);        mHeaderView.setScaleY(1 - mDragOffset / 2);        mDescView.setAlpha(1 - mDragOffset);        requestLayout();  }  @Override  public void onViewReleased(View releasedChild, float xvel, float yvel) {      int top = getPaddingTop();      if (yvel > 0 || (yvel == 0 && mDragOffset > 0.5f)) {          top += mDragRange;      }      mDragHelper.settleCapturedViewAt(releasedChild.getLeft(), top);  }  @Override  public int getViewVerticalDragRange(View child) {      return mDragRange;  }  @Override  public int clampViewPositionVertical(View child, int top, int dy) {      final int topBound = getPaddingTop();      final int bottomBound = getHeight() - mHeaderView.getHeight() - mHeaderView.getPaddingBottom();      final int newTop = Math.min(Math.max(top, topBound), bottomBound);      return newTop;  }}@Overridepublic void computeScroll() {  if (mDragHelper.continueSettling(true)) {      ViewCompat.postInvalidateOnAnimation(this);  }}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {  final int action = MotionEventCompat.getActionMasked(ev);  if (( action != MotionEvent.ACTION_DOWN)) {      mDragHelper.cancel();      return super.onInterceptTouchEvent(ev);  }  if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) {      mDragHelper.cancel();      return false;  }  final float x = ev.getX();  final float y = ev.getY();  boolean interceptTap = false;  switch (action) {      case MotionEvent.ACTION_DOWN: {          mInitialMotionX = x;          mInitialMotionY = y;            interceptTap = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);          break;      }      case MotionEvent.ACTION_MOVE: {          final float adx = Math.abs(x - mInitialMotionX);          final float ady = Math.abs(y - mInitialMotionY);          final int slop = mDragHelper.getTouchSlop();          if (ady > slop && adx > ady) {              mDragHelper.cancel();              return false;          }      }  }  return mDragHelper.shouldInterceptTouchEvent(ev) || interceptTap;}@Overridepublic boolean onTouchEvent(MotionEvent ev) {  mDragHelper.processTouchEvent(ev);  final int action = ev.getAction();    final float x = ev.getX();    final float y = ev.getY();    boolean isHeaderViewUnder = mDragHelper.isViewUnder(mHeaderView, (int) x, (int) y);    switch (action & MotionEventCompat.ACTION_MASK) {      case MotionEvent.ACTION_DOWN: {          mInitialMotionX = x;          mInitialMotionY = y;          break;      }      case MotionEvent.ACTION_UP: {          final float dx = x - mInitialMotionX;          final float dy = y - mInitialMotionY;          final int slop = mDragHelper.getTouchSlop();          if (dx * dx + dy * dy < slop * slop && isHeaderViewUnder) {              if (mDragOffset == 0) {                  smoothSlideTo(1f);              } else {                  smoothSlideTo(0f);              }          }          break;      }  }  return isHeaderViewUnder && isViewHit(mHeaderView, (int) x, (int) y) || isViewHit(mDescView, (int) x, (int) y);}private boolean isViewHit(View view, int x, int y) {    int[] viewLocation = new int[2];    view.getLocationOnScreen(viewLocation);    int[] parentLocation = new int[2];    this.getLocationOnScreen(parentLocation);    int screenX = parentLocation[0] + x;    int screenY = parentLocation[1] + y;    return screenX >= viewLocation[0] && screenX < viewLocation[0] + view.getWidth() &&            screenY >= viewLocation[1] && screenY < viewLocation[1] + view.getHeight();}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {    measureChildren(widthMeasureSpec, heightMeasureSpec);    int maxWidth = MeasureSpec.getSize(widthMeasureSpec);    int maxHeight = MeasureSpec.getSize(heightMeasureSpec);    setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),            resolveSizeAndState(maxHeight, heightMeasureSpec, 0));}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {  mDragRange = getHeight() - mHeaderView.getHeight();    mHeaderView.layout(            0,            mTop,            r,            mTop + mHeaderView.getMeasuredHeight());    mDescView.layout(            0,            mTop + mHeaderView.getMeasuredHeight(),            r,            mTop  + b);}

Code: Https://github.com/flavienlaurent/flavienlaurent.com


Whether it is menudrawer or the DragLayout implemented in this article, it embodies a design philosophy. The controls that can be dragged are encapsulated in a custom Layout. Why? Why not directly add ViewDragHelper. in create (this, 1f, new DragHelperCallback (), replace this with any deployed container, so that the sub-View in this container can be dragged, is a Layout defined separately for processing? I personally think that if you drag a sub-view in the general Layout, there will be no problem, but the original rule world is disrupted, and a separate Layout is used to complete the drag, he has no rules at all, and it's okay to drag it.


 

How to explain the listView1ItemsAdd () function parameters in c,

ListViewItem lvi = new ListViewItem ();
ListView1.Items. Add (lvi );

About ListViewItem
You can go to msdn for details
Msdn.microsoft.com/..m.aspx

Who has the latest version of LSASecretsView downloaded and detailed instructions for use?

Wenku.baidu.com/...7.html

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.