1.侧拉删除_实现滑动
1.初始化ViewDragHelper----*
-
-
-
-
-
- public class SwipeLayout extends FrameLayout {
-
- public SwipeLayout(Context context) {
- this(context, null);
- }
-
- public SwipeLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- mDragHelper = ViewDragHelper.create(this, 1.0f, mCallback);
- }
- ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
-
- @Override
- public boolean tryCaptureView(View view, int id) {
- return false;
- }
- }
- }
2.传递触摸事件---*
-
- @Override
- public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
- return mDragHelper.shouldInterceptTouchEvent(ev);
- };
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
-
- try {
- mDragHelper.processTouchEvent(event);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return true;
- }
3.通过layout方法把布局放在某个位置
(1)布局
Button会拦截触摸事件,所以使用TextView
- <com.itheima.swipelayout.ui.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/sl"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:minHeight="60dp"
- android:background="#44000000" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/tv_call"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:background="#666666"
- android:gravity="center"
- android:text="Call"
- android:textColor="#ffffff" />
-
- <TextView
- android:id="@+id/tv_del"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:background="#ff0000"
- android:gravity="center"
- android:text="Delete"
- android:textColor="#ffffff" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#44ffffff"
- android:gravity="center_vertical"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/iv_image"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginLeft="15dp"
- android:src="@drawable/head_1" />
-
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="15dp"
- android:text="Name" />
- </LinearLayout>
-
- </com.itheima.swipelayout.ui.SwipeLayout>
(2)找到子View的ID
- private View mBackView;
- private View mFrontView;
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mBackView = getChildAt(0);
- mFrontView = getChildAt(1);
- }
(3)获得控件宽高,可以在onMeasure方法中获得,最好在onSizeChanged方法
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
-
- mHeight = mFrontView.getMeasuredHeight();
- mWidth = mFrontView.getMeasuredWidth();
-
- mRange = mBackView.getMeasuredWidth();
-
- }
(4)onLayout
- @Override
- protected void onLayout(boolean changed, int left, int top, int right,
- int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- layoutContent(false);
- }
-
- private void layoutContent(boolean isOpen) {
-
- Rect frontRect = computeFrontViewRect(isOpen);
- mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom);
-
- Rect backRect = computeBackViewViaFront(frontRect);
- mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom);
-
-
- bringChildToFront(mFrontView);
- }
-
-
- private Rect computeFrontViewRect(boolean isOpen) {
- int left = 0;
- if(isOpen){
- left = -mRange;
- }
-
- return new Rect(left, 0, left + mWidth, 0 + mHeight);
- }
-
-
- private Rect computeBackViewViaFront(Rect frontRect) {
- int left = frontRect.right;
- return new Rect(left, 0, left + mRange, 0 + mHeight);
- }
4.重写监听CallBack
(1)onViewPositionChanged-----callBack
因为后View隐藏了,不能拖拽,所以要把前View的偏移量传给后View
把后View的也传递给前View
让两个View首尾相连
-
-
-
- public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
-
-
- if(changedView == mFrontView){
- mBackView.offsetLeftAndRight(dx);
- }else if (changedView == mBackView) {
- mFrontView.offsetLeftAndRight(dx);
- }
-
-
-
-
- invalidate();
-
- };
2.侧拉删除_回调
1.限定滑动范围--------CallBack中
-
- public int clampViewPositionHorizontal(View child, int left, int dx) {
-
-
- if(child == mFrontView){
- if(left > 0){
- return 0;
- }else if(left < -mRange){
- return -mRange;
- }
- }else if (child == mBackView) {
- if(left > mWidth){
- return mWidth;
- }else if (left < mWidth - mRange) {
- return mWidth - mRange;
- }
- }
- return left;
- };
2.当停止滑动时判断是否开启-------------CallBack中
-
- public void onViewReleased(View releasedChild, float xvel, float yvel) {
-
- if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) {
- open();
- }else if (xvel < 0) {
- open();
- }else {
- close();
- }
-
- };
3.开启和关闭和动画
- public void close() {
- Utils.showToast(getContext(), "Close");
- close(true);
- }
- public void close(boolean isSmooth){
- int finalLeft = 0;
- if(isSmooth){
-
- if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }else {
-
- layoutContent(false);
- }
- }
-
- public void open() {
- Utils.showToast(getContext(), "Open");
- open(true);
- }
- public void open(boolean isSmooth){
- int finalLeft = -mRange;
- if(isSmooth){
-
- if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }else {
- layoutContent(true);
- }
- }
-
- @Override
-
- public void computeScroll() {
- super.computeScroll();
-
- if(mDragHelper.continueSettling(true)){
- ViewCompat.postInvalidateOnAnimation(this);
- }
-
- }
4.回调监听
(1)设定监听和状态
- private Status status = Status.Close;
- private OnSwipeLayoutListener swipeLayoutListener;
-
- public Status getStatus() {
- return status;
- }
-
- public void setStatus(Status status) {
- this.status = status;
- }
-
- public OnSwipeLayoutListener getSwipeLayoutListener() {
- return swipeLayoutListener;
- }
-
- public void setSwipeLayoutListener(OnSwipeLayoutListener swipeLayoutListener) {
- this.swipeLayoutListener = swipeLayoutListener;
- }
-
- public static enum Status{
- Close, Open, Draging
- }
- public static interface OnSwipeLayoutListener {
-
- void onClose(SwipeLayout mSwipeLayout);
- void onOpen(SwipeLayout mSwipeLayout);
- void onDraging(SwipeLayout mSwipeLayout);
-
- void onStartClose(SwipeLayout mSwipeLayout);
-
- void onStartOpen(SwipeLayout mSwipeLayout);
- }
(2)监听位置
onViewPositionChanged方法:每次界面变化都会调用,高频调用dispatchSwipeEvent
- public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
-
-
- if(changedView == mFrontView){
- mBackView.offsetLeftAndRight(dx);
- }else if (changedView == mBackView) {
- mFrontView.offsetLeftAndRight(dx);
- }
-
- dispatchSwipeEvent();
-
-
- invalidate();
-
- };
(3)状态的判断和变化
- protected void dispatchSwipeEvent() {
-
- if(swipeLayoutListener != null){
- swipeLayoutListener.onDraging(this);
- }
-
-
- Status preStatus = status;
-
- status = updateStatus();
- if (preStatus != status && swipeLayoutListener != null) {
- if (status == Status.Close) {
- swipeLayoutListener.onClose(this);
- } else if (status == Status.Open) {
- swipeLayoutListener.onOpen(this);
- } else if (status == Status.Draging) {
- if(preStatus == Status.Close){
- swipeLayoutListener.onStartOpen(this);
- }else if (preStatus == Status.Open) {
- swipeLayoutListener.onStartClose(this);
- }
- }
- }
- }
-
- private Status updateStatus() {
-
- int left = mFrontView.getLeft();
- if(left == 0){
- return Status.Close;
- }else if (left == -mRange) {
- return Status.Open;
- }
- return Status.Draging;
- }
3.侧拉删除_放入ListView
1.SwipeLayout完整
-
-
-
-
-
- public class SwipeLayout extends FrameLayout {
- private Status status = Status.Close;
- private OnSwipeLayoutListener swipeLayoutListener;
-
- public Status getStatus() {
- return status;
- }
-
- public void setStatus(Status status) {
- this.status = status;
- }
-
- public OnSwipeLayoutListener getSwipeLayoutListener() {
- return swipeLayoutListener;
- }
-
- public void setSwipeLayoutListener(OnSwipeLayoutListener swipeLayoutListener) {
- this.swipeLayoutListener = swipeLayoutListener;
- }
-
- public static enum Status{
- Close, Open, Draging
- }
- public static interface OnSwipeLayoutListener {
-
- void onClose(SwipeLayout mSwipeLayout);
- void onOpen(SwipeLayout mSwipeLayout);
- void onDraging(SwipeLayout mSwipeLayout);
-
- void onStartClose(SwipeLayout mSwipeLayout);
-
- void onStartOpen(SwipeLayout mSwipeLayout);
- }
-
- public SwipeLayout(Context context) {
- this(context, null);
- }
-
- public SwipeLayout(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public SwipeLayout(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
-
- mDragHelper = ViewDragHelper.create(this, 1.0f, mCallback);
- }
- ViewDragHelper.Callback mCallback = new ViewDragHelper.Callback() {
-
- @Override
- public boolean tryCaptureView(View view, int id) {
- return true;
- }
-
-
- public int clampViewPositionHorizontal(View child, int left, int dx) {
-
-
- if(child == mFrontView){
- if(left > 0){
- return 0;
- }else if(left < -mRange){
- return -mRange;
- }
- }else if (child == mBackView) {
- if(left > mWidth){
- return mWidth;
- }else if (left < mWidth - mRange) {
- return mWidth - mRange;
- }
- }
- return left;
- };
-
- public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
-
-
- if(changedView == mFrontView){
- mBackView.offsetLeftAndRight(dx);
- }else if (changedView == mBackView) {
- mFrontView.offsetLeftAndRight(dx);
- }
-
- dispatchSwipeEvent();
-
-
- invalidate();
-
- };
-
- public void onViewReleased(View releasedChild, float xvel, float yvel) {
-
- if (xvel == 0 && mFrontView.getLeft() < -mRange / 2.0f) {
- open();
- }else if (xvel < 0) {
- open();
- }else {
- close();
- }
-
- };
-
- };
- private ViewDragHelper mDragHelper;
- private View mBackView;
- private View mFrontView;
- private int mHeight;
- private int mWidth;
- private int mRange;
-
-
- @Override
- public boolean onInterceptTouchEvent(android.view.MotionEvent ev) {
- return mDragHelper.shouldInterceptTouchEvent(ev);
- };
-
- protected void dispatchSwipeEvent() {
-
- if(swipeLayoutListener != null){
- swipeLayoutListener.onDraging(this);
- }
-
-
- Status preStatus = status;
-
- status = updateStatus();
- if (preStatus != status && swipeLayoutListener != null) {
- if (status == Status.Close) {
- swipeLayoutListener.onClose(this);
- } else if (status == Status.Open) {
- swipeLayoutListener.onOpen(this);
- } else if (status == Status.Draging) {
- if(preStatus == Status.Close){
- swipeLayoutListener.onStartOpen(this);
- }else if (preStatus == Status.Open) {
- swipeLayoutListener.onStartClose(this);
- }
- }
- }
- }
-
- private Status updateStatus() {
-
- int left = mFrontView.getLeft();
- if(left == 0){
- return Status.Close;
- }else if (left == -mRange) {
- return Status.Open;
- }
- return Status.Draging;
- }
-
- public void close() {
- Utils.showToast(getContext(), "Close");
- close(true);
- }
- public void close(boolean isSmooth){
- int finalLeft = 0;
- if(isSmooth){
-
- if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }else {
- layoutContent(false);
- }
- }
-
- public void open() {
- Utils.showToast(getContext(), "Open");
- open(true);
- }
- public void open(boolean isSmooth){
- int finalLeft = -mRange;
- if(isSmooth){
-
- if(mDragHelper.smoothSlideViewTo(mFrontView, finalLeft, 0)){
- ViewCompat.postInvalidateOnAnimation(this);
- }
- }else {
- layoutContent(true);
- }
- }
-
- @Override
- public void computeScroll() {
- super.computeScroll();
-
- if(mDragHelper.continueSettling(true)){
- ViewCompat.postInvalidateOnAnimation(this);
- }
-
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
-
- try {
- mDragHelper.processTouchEvent(event);
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- return true;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right,
- int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- layoutContent(false);
- }
-
- private void layoutContent(boolean isOpen) {
-
- Rect frontRect = computeFrontViewRect(isOpen);
- mFrontView.layout(frontRect.left, frontRect.top, frontRect.right, frontRect.bottom);
-
- Rect backRect = computeBackViewViaFront(frontRect);
- mBackView.layout(backRect.left, backRect.top, backRect.right, backRect.bottom);
-
-
- bringChildToFront(mFrontView);
- }
-
- private Rect computeBackViewViaFront(Rect frontRect) {
- int left = frontRect.right;
- return new Rect(left, 0, left + mRange, 0 + mHeight);
- }
-
- private Rect computeFrontViewRect(boolean isOpen) {
- int left = 0;
- if(isOpen){
- left = -mRange;
- }
- return new Rect(left, 0, left + mWidth, 0 + mHeight);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mBackView = getChildAt(0);
- mFrontView = getChildAt(1);
- }
-
- @Override
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(w, h, oldw, oldh);
-
- mHeight = mFrontView.getMeasuredHeight();
- mWidth = mFrontView.getMeasuredWidth();
-
- mRange = mBackView.getMeasuredWidth();
-
- }
-
- }
2.ListView
(1)ListView中item布局
- <?xml version="1.0" encoding="utf-8"?>
- <com.itheima.swipelayout.ui.SwipeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/sl"
- android:layout_width="match_parent"
- android:layout_height="60dp"
- android:minHeight="60dp"
- android:background="#44000000" >
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:orientation="horizontal" >
-
- <TextView
- android:id="@+id/tv_call"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:background="#666666"
- android:gravity="center"
- android:text="Call"
- android:textColor="#ffffff" />
-
- <TextView
- android:id="@+id/tv_del"
- android:layout_width="60dp"
- android:layout_height="match_parent"
- android:background="#ff0000"
- android:gravity="center"
- android:text="Delete"
- android:textColor="#ffffff" />
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="#44ffffff"
- android:gravity="center_vertical"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/iv_image"
- android:layout_width="40dp"
- android:layout_height="40dp"
- android:layout_marginLeft="15dp"
- android:src="@drawable/head_1" />
-
- <TextView
- android:id="@+id/tv_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginLeft="15dp"
- android:text="Name" />
- </LinearLayout>
-
- </com.itheima.swipelayout.ui.SwipeLayout>
(2)MyAdapter
- public class MyAdapter extends BaseAdapter {
-
- protected static final String TAG = "TAG";
-
-
- public MyAdapter(Context context) {
- super();
- this.context = context;
-
- opendItems = new ArrayList<SwipeLayout>();
- }
-
- private Context context;
- private ArrayList<SwipeLayout> opendItems;
-
- @Override
- public int getCount() {
- return NAMES.length;
- }
-
- @Override
- public Object getItem(int position) {
- return NAMES[position];
- }
-
- @Override
- public long getItemId(int position) {
-
- return position;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
-
- View view = convertView;
- if(convertView == null){
- view = View.inflate(context, R.layout.item_list, null);
-
- }
- ViewHolder mHolder = ViewHolder.getHolder(view);
-
- SwipeLayout sl = (SwipeLayout)view;
- sl.setSwipeLayoutListener(new OnSwipeLayoutListener() {
-
- @Override
- public void onStartOpen(SwipeLayout mSwipeLayout) {
- Log.d(TAG, "onStartOpen");
-
-
-
- for (SwipeLayout layout : opendItems) {
- layout.close();
- }
-
- opendItems.clear();
- }
-
- @Override
- public void onStartClose(SwipeLayout mSwipeLayout) {
- Log.d(TAG, "onStartClose");
- }
-
- @Override
- public void onOpen(SwipeLayout mSwipeLayout) {
- Log.d(TAG, "onOpen");
-
- opendItems.add(mSwipeLayout);
- }
- @Override
- public void onDraging(SwipeLayout mSwipeLayout) {
- }
-
- @Override
- public void onClose(SwipeLayout mSwipeLayout) {
- Log.d(TAG, "onClose");
-
- opendItems.remove(mSwipeLayout);
- }
- });
- return view;
- }
-
- static class ViewHolder {
- TextView tv_call;
- TextView tv_del;
-
- public static ViewHolder getHolder(View view) {
- Object tag = view.getTag();
- if(tag == null){
- ViewHolder viewHolder = new ViewHolder();
- viewHolder.tv_call = (TextView)view.findViewById(R.id.tv_call);
- viewHolder.tv_del = (TextView)view.findViewById(R.id.tv_del);
- tag = viewHolder;
- view.setTag(tag);
- }
- return (ViewHolder)tag;
- }
- }
-
- }
以上主要主要摘自http://blog.csdn.net/u012360634/article/details/49663557
优化:监听ListView滚动时关闭所有打开的
接下来是原创解决方法
1.解决listview的上下拉动和自定义view的左右拉动时的事件冲突
在自定义view初始化的时候,也初始化手势监听器
public leftDeleteView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// a.初始化
viewDragHelper = ViewDragHelper.create(this, 1.0f, mCallback);
gestureDetector = new GestureDetector(context, getstureListener);
}
GestureDetector.SimpleOnGestureListener getstureListener = new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
// 当横向移动距离大于等于纵向时,返回true
return Math.abs(distanceX) >= Math.abs(distanceY);
}
};
然后在onInterceptTouchEvent中根据上下和左右的位移差来判断是否对触摸事件进行拦截
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
// 决定当前的SwipeLayout是否要把touch事件拦截下来,直接交由自己的onTouchEvent处理
// 返回true则为拦截
return viewDragHelper.shouldInterceptTouchEvent(ev) & gestureDetector.onTouchEvent(ev);
}
如果返回的时true的话,那么就会进入该view的
onTouchEvent方法中,我们再在这个方法中
上下和左右的位移差判断是否响应触摸事件
@Override
public boolean onTouchEvent(MotionEvent event) {
// 当处理touch事件时,不希望被父类onInterceptTouchEvent的代码所影响。
// 比如处理向右滑动关闭已打开的条目时,如果进行以下逻辑,则不会在关闭的同时引发左边菜单的打开。
switch (MotionEventCompat.getActionMasked(event)) {
case MotionEvent.ACTION_DOWN:
mDownX = event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
float deltaX = event.getRawX() - mDownX;
//viewDragHelper.getTouchSlop()//viewDragHelper向上滑动的距离
//Log.i("xuqunxing", "deltaX:"+deltaX+",heigh:"+ viewDragHelper.getTouchSlop());
if (Math.abs(deltaX)> viewDragHelper.getTouchSlop()) {
Log.i("xuqunxing", "requestDisallowInterceptTouchEvent");
// 请求父级View不拦截touch事件
requestDisallowInterceptTouchEvent(true);
}
break;
case MotionEvent.ACTION_UP:
mDownX = 0;
default:
break;
}
viewDragHelper.processTouchEvent(event);
return true;// 设置为true才能触摸到,才能拖动
}
这样就解决了,源码地址:http://download.csdn.net/detail/iblue007/9369406
最后上图