1.实现原理
2.实现自定义左滑View
// 左边显示内容的View
private View leftContentView;
// 右边操作的View
private View rightActionView;
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() < 2) {
throw new IllegalArgumentException("child view less than 2!!");
}
leftContentView = getChildAt(0);
rightActionView = getChildAt(1);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 测量子View的宽高
measureChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
/*
*(0,0) (左width,0)
* -------------- --------------
* | 左 | | 右 |
* -------------- (左width,左height)-------------- (左width+右width,右height)
*/
int leftLeft = 0;
int leftTop = 0;
int leftRight = leftContentView.getMeasuredWidth();
int leftBottom = leftContentView.getMeasuredHeight();
leftContentView.layout(leftLeft, leftTop, leftRight, leftBottom);
int rightLeft = leftContentView.getMeasuredWidth();
int rightTop = 0;
int rightRight = leftContentView.getMeasuredWidth() + rightActionView.getMeasuredWidth();
int rightBottom = rightActionView.getMeasuredHeight();
rightActionView.layout(rightLeft, rightTop, rightRight, rightBottom);
}
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.welcom.slide.action.view.SlideActionView
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@android:color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="小马哥" />
LinearLayout>
<LinearLayout
android:layout_width="100dp"
android:layout_height="match_parent">
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#ff0000"
android:gravity="center"
android:text="删除" />
<TextView
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#ff0000"
android:gravity="center"
android:text="拉黑" />
LinearLayout>
com.welcom.slide.action.view.SlideActionView>
LinearLayout>
运行效果:
可以看到和我们的原理图一样了,左边显示内容区域,右边因为在屏幕外,暂时看不到。
// 是否滑动到右边
private boolean isShowRightView = false;
// 滑动辅助类
private ViewDragHelper helper;
public SlideActionView(Context context) {
this(context, null);
}
public SlideActionView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlideActionView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
helper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(@NonNull View child, int pointerId) {
//捕获需要滑动的View,这里返回true
return true;
}
@Override
public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
//如果左边控件拖动,我们要让右边控件也重新布局,反之
if (changedView == leftContentView) {
rightActionView.layout(rightActionView.getLeft() + dx, 0, rightActionView.getRight() + dx, rightActionView.getBottom() + dy);
} else if (changedView == rightActionView) {
leftContentView.layout(leftContentView.getLeft() + dx, 0, leftContentView.getRight() + dx, leftContentView.getBottom() + dy);
}
}
@Override
public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
//对左右越界问题的处理
if (child == leftContentView) {
//处理两边的越界问题
if (left >= 0) {
left = 0;
} else if (left <= -rightActionView.getMeasuredWidth()) {
left = -rightActionView.getMeasuredWidth();
}
} else if (child == rightActionView) {
if (left <= leftContentView.getMeasuredWidth() - rightActionView.getMeasuredWidth()) {
left = leftContentView.getMeasuredWidth() - rightActionView.getMeasuredWidth();
} else if (left >= leftContentView.getMeasuredWidth()) {
left = leftContentView.getMeasuredWidth();
}
}
return left;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
//松开后,什么时候打开rightActionView,什么时候关闭leftContentView
//临界值,rightActionView.getLeft() 和 屏幕的宽度-rightActionView.getWidth()/2
if (releasedChild == leftContentView) {
if (rightActionView.getLeft() < getMeasuredWidth() - rightActionView.getMeasuredWidth() / 2) {
//使用ViewDragHelper来滑动
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth() - rightActionView.getMeasuredWidth(), 0);
isShowRightView = true;
invalidate();
} else {
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth(), 0);
isShowRightView = false;
invalidate();
}
} else if (releasedChild == rightActionView) {
if (rightActionView.getLeft() < getMeasuredWidth() - rightActionView.getMeasuredWidth() / 2) {
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth() - rightActionView.getMeasuredWidth(), 0);
isShowRightView = true;
invalidate();
} else {
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth(), 0);
isShowRightView = false;
invalidate();
}
}
}
});
}
@Override
public void computeScroll() {
if (helper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
//处理父视图接收的触摸事件。此方法将调度回调事件。
helper.processTouchEvent(event);
return true;
}
public class SlideRecyclerView extends RecyclerView {
public SlideRecyclerView(Context context) {
super(context);
}
public SlideRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public SlideRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
try {
if (SlideActionView.isShowRightView()) {
if (SlideActionView.disTouchArea(ev)) {
return super.dispatchTouchEvent(ev);
} else {
SlideActionView.restorePosition();
return true;
}
}
} catch (Exception e) {
//ignore
}
return super.dispatchTouchEvent(ev);
}
}
public class SlideActionView extends ViewGroup {
private static SlideActionView slideActionView = null;
// 左边显示内容的View
private View leftContentView;
// 右边操作的View
private View rightActionView;
// 是否滑动到右边
private boolean isShowRightView = false;
// 滑动辅助类
private ViewDragHelper helper;
private ISlideRightActionOnClickListener rightActionOnClickListener;
public void setRightActionOnClickListener(ISlideRightActionOnClickListener rightActionOnClickListener) {
this.rightActionOnClickListener = rightActionOnClickListener;
}
public SlideActionView(Context context) {
this(context, null);
}
public SlideActionView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public SlideActionView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView();
}
private void initView() {
helper = ViewDragHelper.create(this, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(@NonNull View child, int pointerId) {
//捕获需要滑动的View,这里返回true
return true;
}
@Override
public void onViewPositionChanged(@NonNull View changedView, int left, int top, int dx, int dy) {
//如果左边控件拖动,我们要让右边控件也重新布局,反之
if (changedView == leftContentView) {
rightActionView.layout(rightActionView.getLeft() + dx, 0, rightActionView.getRight() + dx, rightActionView.getBottom() + dy);
} else if (changedView == rightActionView) {
leftContentView.layout(leftContentView.getLeft() + dx, 0, leftContentView.getRight() + dx, leftContentView.getBottom() + dy);
}
}
@Override
public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
//对左右越界问题的处理
if (child == leftContentView) {
//处理两边的越界问题
if (left >= 0) {
left = 0;
} else if (left <= -rightActionView.getMeasuredWidth()) {
left = -rightActionView.getMeasuredWidth();
}
} else if (child == rightActionView) {
if (left <= leftContentView.getMeasuredWidth() - rightActionView.getMeasuredWidth()) {
left = leftContentView.getMeasuredWidth() - rightActionView.getMeasuredWidth();
} else if (left >= leftContentView.getMeasuredWidth()) {
left = leftContentView.getMeasuredWidth();
}
}
return left;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
//松开后,什么时候打开rightActionView,什么时候关闭leftContentView
//临界值,rightActionView.getLeft() 和 屏幕的宽度-rightActionView.getWidth()/4
if (releasedChild == leftContentView) {
if (rightActionView.getLeft() < getMeasuredWidth() - rightActionView.getMeasuredWidth() / 4) {
//使用ViewDragHelper来滑动
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth() - rightActionView.getMeasuredWidth(), 0);
isShowRightView = true;
invalidate();
} else {
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth(), 0);
isShowRightView = false;
invalidate();
}
} else if (releasedChild == rightActionView) {
if (rightActionView.getLeft() < getMeasuredWidth() - rightActionView.getMeasuredWidth() / 2) {
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth() - rightActionView.getMeasuredWidth(), 0);
isShowRightView = true;
invalidate();
} else {
helper.smoothSlideViewTo(rightActionView, getMeasuredWidth(), 0);
isShowRightView = false;
invalidate();
}
}
}
});
}
@Override
public void computeScroll() {
if (helper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
} else {
if (isShowRightView) {
slideActionView = this;
} else {
slideActionView = null;
}
}
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouchEvent(MotionEvent event) {
//处理父视图接收的触摸事件。此方法将调度回调事件。
helper.processTouchEvent(event);
return true;
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() < 2) {
throw new IllegalArgumentException("child view less than 2!!");
}
leftContentView = getChildAt(0);
rightActionView = getChildAt(1);
if (rightActionView instanceof ViewGroup) {
for (int i = 0; i < ((ViewGroup) rightActionView).getChildCount(); i++) {
((ViewGroup) rightActionView).getChildAt(i).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (rightActionOnClickListener != null) {
rightActionOnClickListener.onClick(v);
}
}
});
}
} else {
rightActionView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (rightActionOnClickListener != null) {
rightActionOnClickListener.onClick(v);
}
}
});
}
}
public static boolean disTouchArea(MotionEvent ev) {
if (slideActionView == null) return false;
float rawX = ev.getRawX();
float rawY = ev.getRawY();
int[] location = new int[2];
slideActionView.getLocationOnScreen(location);
Log.i("wxq", "rawX->" + rawX);
Log.i("wxq", "rawY->" + rawY);
Log.i("wxq", "locationX->" + location[0]);
Log.i("wxq", "locationY->" + location[1]);
return rawX > location[0] && rawX < (slideActionView.getMeasuredWidth() + location[0])
&& rawY > location[1] && rawY < (slideActionView.getMeasuredHeight() + location[1]);
}
public static boolean isShowRightView() {
return slideActionView != null;
}
//还原位置
public static void restorePosition() {
if (!isShowRightView()) {
return;
}
try {
if (slideActionView.helper.continueSettling(true)) return;
slideActionView.helper.smoothSlideViewTo(slideActionView.rightActionView, slideActionView.getMeasuredWidth(), 0);
slideActionView.isShowRightView = false;
slideActionView.invalidate();
} catch (Exception e) {
//ignore
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 测量子View的宽高
measureChildren(widthMeasureSpec, heightMeasureSpec);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
/*
*(0,0) (左width,0)
* -------------- --------------
* | 左 | | 右 |
* -------------- (左width,左height)-------------- (左width+右width,右height)
*/
int leftLeft = 0;
int leftTop = 0;
int leftRight = leftContentView.getMeasuredWidth();
int leftBottom = leftContentView.getMeasuredHeight();
leftContentView.layout(leftLeft, leftTop, leftRight, leftBottom);
int rightLeft = leftContentView.getMeasuredWidth();
int rightTop = 0;
int rightRight = leftContentView.getMeasuredWidth() + rightActionView.getMeasuredWidth();
int rightBottom = rightActionView.getMeasuredHeight();
rightActionView.layout(rightLeft, rightTop, rightRight, rightBottom);
}
public interface ISlideRightActionOnClickListener {
void onClick(View view);
}
}
#####传送门git示例代码