package com.android.view; /* 此类实现滑动删除布局 */ 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.view.WindowManager; import android.widget.LinearLayout; /** * Created by Bruce on 11/24/14. */ public class SwipeLayout extends LinearLayout { private ViewDragHelper viewDragHelper; private View contentView; private View actionView; private int dragDistance; private final double AUTO_OPEN_SPEED_LIMIT = 800.0; private int draggedX; public SwipeLayout(Context context) { this(context, null); } public SwipeLayout(Context context, AttributeSet attrs) { this(context, attrs, -1); } public SwipeLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); viewDragHelper = ViewDragHelper.create(this, new DragHelperCallback()); } //在SwipeLayout的inflate事件中,获取到contentView和actionView @Override protected void onFinishInflate() { contentView = getChildAt(0); actionView = getChildAt(1); actionView.setVisibility(GONE); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //在SwipeLayout的measure事件中,设置拖动的距离为actionView的宽度 dragDistance = actionView.getMeasuredWidth(); } private class DragHelperCallback extends ViewDragHelper.Callback { //用来确定contentView和actionView是可以拖动的 @Override public boolean tryCaptureView(View view, int i) { return view == contentView || view == actionView; } //onViewPositionChanged在被拖动的view位置改变的时候调用, // 如果被拖动的view是contentView,我们需要在这里更新actionView的位置,反之亦然。 @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { draggedX = left; if (changedView == contentView) { actionView.offsetLeftAndRight(dx); } else { contentView.offsetLeftAndRight(dx); } if (actionView.getVisibility() == View.GONE) { actionView.setVisibility(View.VISIBLE); } invalidate(); } //clampViewPositionHorizontal用来限制view在x轴上拖动, //要实现水平拖动效果必须要实现这个方法,我们这里因为仅仅需要实现水平拖动,所以没有实现clampViewPositionVertical方法。 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == contentView) { final int leftBound = getPaddingLeft(); final int minLeftBound = -leftBound - dragDistance; final int newLeft = Math.min(Math.max(minLeftBound, left), 0); return newLeft; } else { final int minLeftBound = getPaddingLeft() + contentView.getMeasuredWidth() - dragDistance; final int maxLeftBound = getPaddingLeft() + contentView.getMeasuredWidth() + getPaddingRight(); final int newLeft = Math.min(Math.max(left, minLeftBound), maxLeftBound); return newLeft; } } //getViewHorizontalDragRange方法用来限制view可以拖动的范围 @Override public int getViewHorizontalDragRange(View child) { return dragDistance; } //根据滑动手势的速度以及滑动的距离来确定是否显示actionView。 //smoothSlideViewTo方法用来在滑动手势之后实现惯性滑动效果 @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); boolean settleToOpen = false; if (xvel > AUTO_OPEN_SPEED_LIMIT) { settleToOpen = false; } else if (xvel < -AUTO_OPEN_SPEED_LIMIT) { settleToOpen = true; } else if (draggedX <= -dragDistance / 2) { settleToOpen = true; } else if (draggedX > -dragDistance / 2) { settleToOpen = false; } final int settleDestX = settleToOpen ? -dragDistance : 0; viewDragHelper.smoothSlideViewTo(contentView, settleDestX, 0); ViewCompat.postInvalidateOnAnimation(SwipeLayout.this); } } /* onInterceptTouchEvent()用于处理事件并改变事件的传递方向。 返回值为false时事件会传递给子控件的onInterceptTouchEvent(); 返回值为true时事件会传递给当前控件的onTouchEvent(),而不在传递给子控件,这就是所谓的Intercept(截断)。 onTouchEvent() 用于处理事件,返回值决定当前控件是否消费(consume)了这个事件。 可能你要问是否消费了又区别吗,反正我已经针对事件编写了处理代码? 答案是有区别!比如ACTION_MOVE或者ACTION_UP发生的前提是一定曾经发生了ACTION_DOWN, 如果你没有消费ACTION_DOWN,那么系统会认为ACTION_DOWN没有发生过,所以ACTION_MOVE或者ACTION_UP就不能被捕获。 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { Log.i("fenghaitao", "=====onInterceptTouchEvent===="); if(viewDragHelper.shouldInterceptTouchEvent(ev)) { return true; } return super.onInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE); int width = wm.getDefaultDisplay().getWidth(); int height = wm.getDefaultDisplay().getHeight(); Log.i("fenghaitao","==========onTouchEvent======"+event.getX()+" ,==width="+width+" , ===height="+height); if(event.getX() > width*0.6) { viewDragHelper.processTouchEvent(event); return true; } return false; } @Override public void computeScroll() { super.computeScroll(); if(viewDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } }