Android development: Using ViewDragHelper to achieve drawer stretch
In fact, there are many ways to achieve a Layout drawer stretch effect. The most common method is to customize a ViewGroup, then control click events, control movement, and so on, this method has a large amount of code and is complicated to implement. It is also troublesome to add other effects to the maintenance in the later stage. Until today, we have seen the ViewDragHelper class, which is generated specifically for moving the View, I tried to develop a drawer stretching effect,
All the movement control is implemented in ViewDragHelper. Callback, and dragHelper. smoothSlideViewTo is used for movement. Besides, Callback integrates many methods to facilitate later maintenance or add other functions.
First, let's take a look at the core DragLayout code.
public class DragLayout extends LinearLayout { private ViewDragHelper dragHelper; private View mDragView, contentView; private int dragRange; public DragLayout(Context context) { super(context); init(); } public DragLayout(Context context, AttributeSet attrs) { super(context, attrs); init(); } @TargetApi(Build.VERSION_CODES.LOLLIPOP) public DragLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); init(); } public DragLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { dragHelper = ViewDragHelper.create(this, callback); } @Override protected void onFinishInflate() { super.onFinishInflate(); mDragView = findViewById(R.id.dragView); contentView = findViewById(R.id.contentView); } private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return child == mDragView; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { contentView.layout(0, top + mDragView.getHeight(), getWidth(), top + mDragView.getHeight() + dragRange); } @Override public int clampViewPositionVertical(View child, int top, int dy) { int topBound = getHeight() - dragRange - mDragView.getHeight(); int bottomBound = getHeight() - mDragView.getHeight(); final int newHeight = Math.min(Math.max(topBound, top), bottomBound); return newHeight; } @Override public int getViewVerticalDragRange(View child) { return dragRange; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if (yvel > 0) { smoothToBottom(); }else if (yvel < 0) { smoothToTop(); } } }; @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); dragRange = contentView.getMeasuredHeight(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mDragView.layout(0, getHeight() - mDragView.getHeight(), getWidth(), getHeight()); contentView.layout(0, getHeight(), getWidth(), getHeight() + dragRange); } @Override public boolean onInterceptHoverEvent(MotionEvent event) { final int action = MotionEventCompat.getActionMasked(event); if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { dragHelper.cancel(); return false; } return dragHelper.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { dragHelper.processTouchEvent(event); return true; } private void smoothToTop() { if (dragHelper.smoothSlideViewTo(mDragView, getPaddingLeft(), getHeight() - dragRange - mDragView.getHeight())) { ViewCompat.postInvalidateOnAnimation(this); } } private void smoothToBottom() { if (dragHelper.smoothSlideViewTo(mDragView, getPaddingLeft(), getHeight() - mDragView.getHeight())) { ViewCompat.postInvalidateOnAnimation(this); } } @Override public void computeScroll() { if (dragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } }}
In this case, ViewDragHelper is initialized.
dragHelper = ViewDragHelper.create(this, callback);
Set the moving distance in the vertical direction. Here, set it to the height of listview:
@ Override
Public int clampViewPositionVertical (View child, int top, int dy ){
Int topBound = getHeight ()-dragRange-mDragView. getHeight ();
Int bottomBound = getHeight ()-mDragView. getHeight ();
Final int newHeight = Math. min (Math. max (topBound, top), bottomBound );
Return newHeight;
}
Move the position of the listener, move the listview, and keep it under the DrawView:
@Overridepublic void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { contentView.layout(0, top + mDragView.getHeight(), getWidth(), top + mDragView.getHeight() + dragRange);}
Relayout in OnLayout to hide listView:
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mDragView.layout(0, getHeight() - mDragView.getHeight(), getWidth(), getHeight()); contentView.layout(0, getHeight(), getWidth(), getHeight() + dragRange); }
Next is the XML layout:
Very simple. Put two views in the Custom View.
The last MainActivity:
public class MainActivity extends AppCompatActivity { String[] listItems = {item 1, item 2 , list, android, item 3, foobar, bar, }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ListView listView = (ListView) findViewById(R.id.contentView); listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, listItems)); }}
Finally, this Demo only implements a very simple function, but we can see that ViewDragHelper is powerful. We strongly recommend that you solve it. This is the address of the two APIs.
ViewDraghelper
Callback