1 引言
android support v4中比较强大的类ViewDragHelper。自定义View(三) switch开关按钮 ViewDragHelper的使用初级 该文章粗略简述了ViewDragHelper的使用。本文进一步升级 使用ViewDragHelper类实现侧滑效果。注这里实现效果类似侧拉删除效果。(如果想实现侧拉删除效果需要自定义回调函数和处理逻辑 参照本文也可以实现自己的slidebar)
2 布局
均较为简单 可根据自己的需求更改:
(1)left_view.xml布局如下:为学号和姓名
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ccc"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="20dp"
android:text="姓名"
android:textColor="#f03744"
android:textSize="18sp" />
<TextView
android:paddingLeft="20dp"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="学号"
android:textColor="#f03744"
android:textSize="18sp" />
</LinearLayout>
(2)right_view.xml 为编辑按钮
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="#4690BD"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:paddingLeft="20dp"
android:text="删除"
android:textColor="#f03744"
android:textSize="18sp" />
<TextView
android:paddingLeft="20dp"
android:gravity="center"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:text="编辑"
android:textColor="#f03744"
android:textSize="18sp" />
</LinearLayout>
(3) 主要布局 activity_main
com.example.myswipedemo.MySwipeView为本文自定义的ViewGroup 为简便本文继承RelativeLayout<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <com.example.myswipedemo.MySwipeView android:layout_width="match_parent" android:layout_height="60dp" android:layout_gravity="center_horizontal" android:orientation="horizontal" > <include layout="@layout/left_view" android:id="@+id/lview" /> <include layout="@layout/right_view" android:id="@+id/rview"/> </com.example.myswipedemo.MySwipeView> </LinearLayout>
3 自定义的ViewGroup
public class MySwipeView extends RelativeLayout { private ViewDragHelper mDragger; private int mRange; View mLeftView; //正常显示的View View mRightView;//编辑模式下显示的View private int mRightWidth; //右边View的宽度 public MySwipeView(Context context) { this(context, null); } public MySwipeView(Context context, AttributeSet attrs) { this(context, attrs, 0); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) public MySwipeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mDragger.shouldInterceptTouchEvent(ev); } @Override public boolean onTouchEvent(MotionEvent event) { mDragger.processTouchEvent(event); return true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mLeftView = getChildAt(0); mRightView = getChildAt(1); int left = getMeasuredWidth();//左边此时完全显示 宽度是整个View宽度 //左边View放于左边View的右边 超出屏幕 故不显示 mRightView.layout(left, 0, left + mRightView.getMeasuredWidth(), mRightView.getMeasuredHeight()); mRange = left - mRightView.getMeasuredWidth(); mRightWidth = mRightView.getWidth(); } @Override public void computeScroll() { //ViewCompat.postInvalidateOnAnimation //不断回调此函数 if (mDragger.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(this); } } @Override protected void onFinishInflate() { super.onFinishInflate(); mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {//初始化ViewDragHelper @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (child == mLeftView) { //左侧View 的left 值 最大为0 最小为 -mRightWidth left = Math.min(0,Math.max(-mRightWidth, left)); } if (child == mRightView) {//同上 left = Math.min(mLeftView.getWidth()+mRightWidth,Math.max(mLeftView.getWidth()-mRightWidth,left)); } return left; } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { if (xvel > 0) {//显示左边view mDragger.smoothSlideViewTo(mLeftView,0, 0); } else if((xvel == 0) && (mLeftView.getLeft() > (-mRightWidth / 3))) {//显示左边view mDragger.smoothSlideViewTo(mLeftView,0, 0); }else if((xvel == 0) && (mLeftView.getLeft() <= (-mRightWidth / 3))){ mDragger.smoothSlideViewTo(mLeftView,-mRightWidth, 0); }else if(xvel <0){ mDragger.smoothSlideViewTo(mLeftView,-mRightWidth, 0); } ViewCompat.postInvalidateOnAnimation(MySwipeView.this);; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { if (changedView == mLeftView) { mRightView.offsetLeftAndRight(dx); } else if (changedView == mRightView) { mLeftView.offsetLeftAndRight(dx); } ViewCompat.postInvalidateOnAnimation(MySwipeView.this);;//一定要刷新,不然会没效果 } @Override public int getViewHorizontalDragRange(View child) { return mRange; } }); } }
(1) ViewDragHelper的初始化本文不再赘述。ViewGroup的自定义分别经历如下步骤:a onMeasure 在onMeasure中计算childView的测量值以及模式,以及设置自己的宽和高:b onLayout对其所有childView进行定位
c dispatchDraw 本文用不上。(2)使用getChildAt()获取xml中的子View(3)使用getMeasuredWidth()获取测量后的宽(4)mRightWidth左边未显示(超出屏幕)的view的宽度(5) public int clampViewPositionHorizontal(View child, int left, int dx)
为水平拉动后View的left值(为变化后的值)与上一节类似不再赘述。(6)如下函数为本文重点:View的位置改变的时候public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy)
该句实现 拉动左边View 将移动距离dx 同时交给右边Viewif (changedView == mLeftView) { mRightView.offsetLeftAndRight(dx); } ViewCompat.postInvalidateOnAnimation(MySwipeView.this);;//一定要刷新,不然会没效果
(7) public void onViewReleased(View releasedChild, float xvel, float yvel ) 实现松开View 弹回或显示右边View里面的 mDragger.smoothSlideViewTo(mLeftView,0, 0); 第一个参数是滑动的View 后面两个参数是View最后的left 和top回调computeScroll()来实现平滑移动。