http://blog.csdn.net/top_code/article/details/17965743


微信对话列表滑动删除效果很不错的,借鉴了github上SwipeListView(项目地址:https://github.com/likebamboo/SwipeListView),在其上进行了一些重构,最终实现了微信对话列表滑动删除效果。


实现原理
1.通过ListView的pointToPosition(int x, int y)来获取按下的position,然后通过android.view.ViewGroup.getChildAt(position)来得到滑动对象swipeView
2.在onTouchEvent中计算要滑动的距离,调用swipeView.scrollTo即可。


运行效果如下







下面是最核心的部分SwipeListView代码:

[java] view plain copy
  1. package com.fxsky.swipelist.widget;  
  2.   
  3. import android.annotation.SuppressLint;  
  4. import android.content.Context;  
  5. import android.content.res.TypedArray;  
  6. import android.os.Handler;  
  7. import android.os.Message;  
  8. import android.util.AttributeSet;  
  9. import android.view.MotionEvent;  
  10. import android.view.View;  
  11. import android.widget.ListView;  
  12.   
  13. import com.fxsky.swipelist.R;  
  14.   
  15. public class SwipeListView extends ListView {  
  16.     private Boolean mIsHorizontal;  
  17.   
  18.     private View mPreItemView;  
  19.   
  20.     private View mCurrentItemView;  
  21.   
  22.     private float mFirstX;  
  23.   
  24.     private float mFirstY;  
  25.   
  26.     private int mRightViewWidth;  
  27.   
  28.     // private boolean mIsInAnimation = false;  
  29.     private final int mDuration = 100;  
  30.   
  31.     private final int mDurationStep = 10;  
  32.   
  33.     private boolean mIsShown;  
  34.   
  35.     public SwipeListView(Context context) {  
  36.         this(context,null);  
  37.     }  
  38.   
  39.     public SwipeListView(Context context, AttributeSet attrs) {  
  40.         this(context, attrs,0);  
  41.     }  
  42.   
  43.     public SwipeListView(Context context, AttributeSet attrs, int defStyle) {  
  44.         super(context, attrs, defStyle);  
  45.           
  46.         TypedArray mTypedArray = context.obtainStyledAttributes(attrs,    
  47.                 R.styleable.swipelistviewstyle);    
  48.           
  49.       //获取自定义属性和默认值    
  50.       mRightViewWidth = (int) mTypedArray.getDimension(R.styleable.swipelistviewstyle_right_width, 200);     
  51.         
  52.       mTypedArray.recycle();    
  53.     }  
  54.   
  55.     /** 
  56.      * return true, deliver to listView. return false, deliver to child. if 
  57.      * move, return true 
  58.      */  
  59.     @Override  
  60.     public boolean onInterceptTouchEvent(MotionEvent ev) {  
  61.         float lastX = ev.getX();  
  62.         float lastY = ev.getY();  
  63.         switch (ev.getAction()) {  
  64.             case MotionEvent.ACTION_DOWN:  
  65.                 mIsHorizontal = null;  
  66.                 System.out.println("onInterceptTouchEvent----->ACTION_DOWN");  
  67.                 mFirstX = lastX;  
  68.                 mFirstY = lastY;  
  69.                 int motionPosition = pointToPosition((int)mFirstX, (int)mFirstY);  
  70.   
  71.                 if (motionPosition >= 0) {  
  72.                     View currentItemView = getChildAt(motionPosition - getFirstVisiblePosition());  
  73.                     mPreItemView = mCurrentItemView;  
  74.                     mCurrentItemView = currentItemView;  
  75.                 }  
  76.                 break;  
  77.   
  78.             case MotionEvent.ACTION_MOVE:  
  79.                 float dx = lastX - mFirstX;  
  80.                 float dy = lastY - mFirstY;  
  81.   
  82.                 if (Math.abs(dx) >= 5 && Math.abs(dy) >= 5) {  
  83.                     return true;  
  84.                 }  
  85.                 break;  
  86.   
  87.             case MotionEvent.ACTION_UP:  
  88.             case MotionEvent.ACTION_CANCEL:  
  89.                 System.out.println("onInterceptTouchEvent----->ACTION_UP");  
  90.                 if (mIsShown && (mPreItemView != mCurrentItemView || isHitCurItemLeft(lastX))) {  
  91.                     System.out.println("1---> hiddenRight");  
  92.                     /** 
  93.                      * 情况一: 
  94.                      * 

     

  95.                      * 一个Item的右边布局已经显示, 
  96.                      * 

     

  97.                      * 这时候点击任意一个item, 那么那个右边布局显示的item隐藏其右边布局 
  98.                      */  
  99.                     hiddenRight(mPreItemView);  
  100.                 }  
  101.                 break;  
  102.         }  
  103.   
  104.         return super.onInterceptTouchEvent(ev);  
  105.     }  
  106.   
  107.     private boolean isHitCurItemLeft(float x) {  
  108.         return x < getWidth() - mRightViewWidth;  
  109.     }  
  110.   
  111.     /** 
  112.      * @param dx 
  113.      * @param dy 
  114.      * @return judge if can judge scroll direction 
  115.      */  
  116.     private boolean judgeScrollDirection(float dx, float dy) {  
  117.         boolean canJudge = true;  
  118.   
  119.         if (Math.abs(dx) > 30 && Math.abs(dx) > 2 * Math.abs(dy)) {  
  120.             mIsHorizontal = true;  
  121.             System.out.println("mIsHorizontal---->" + mIsHorizontal);  
  122.         } else if (Math.abs(dy) > 30 && Math.abs(dy) > 2 * Math.abs(dx)) {  
  123.             mIsHorizontal = false;  
  124.             System.out.println("mIsHorizontal---->" + mIsHorizontal);  
  125.         } else {  
  126.             canJudge = false;  
  127.         }  
  128.   
  129.         return canJudge;  
  130.     }  
  131.   
  132.     /** 
  133.      * return false, can't move any direction. return true, cant't move 
  134.      * vertical, can move horizontal. return super.onTouchEvent(ev), can move 
  135.      * both. 
  136.      */  
  137.     @Override  
  138.     public boolean onTouchEvent(MotionEvent ev) {  
  139.         float lastX = ev.getX();  
  140.         float lastY = ev.getY();  
  141.   
  142.         switch (ev.getAction()) {  
  143.             case MotionEvent.ACTION_DOWN:  
  144.                 System.out.println("---->ACTION_DOWN");  
  145.                 break;  
  146.   
  147.             case MotionEvent.ACTION_MOVE:  
  148.                 float dx = lastX - mFirstX;  
  149.                 float dy = lastY - mFirstY;  
  150.   
  151.                 // confirm is scroll direction  
  152.                 if (mIsHorizontal == null) {  
  153.                     if (!judgeScrollDirection(dx, dy)) {  
  154.                         break;  
  155.                     }  
  156.                 }  
  157.   
  158.                 if (mIsHorizontal) {  
  159.                     if (mIsShown && mPreItemView != mCurrentItemView) {  
  160.                         System.out.println("2---> hiddenRight");  
  161.                         /** 
  162.                          * 情况二: 
  163.                          * 

     

  164.                          * 一个Item的右边布局已经显示, 
  165.                          * 

     

  166.                          * 这时候左右滑动另外一个item,那个右边布局显示的item隐藏其右边布局 
  167.                          * 

     

  168.                          * 向左滑动只触发该情况,向右滑动还会触发情况五 
  169.                          */  
  170.                         hiddenRight(mPreItemView);  
  171.                     }  
  172.   
  173.                     if (mIsShown && mPreItemView == mCurrentItemView) {  
  174.                         dx = dx - mRightViewWidth;  
  175.                         System.out.println("======dx " + dx);  
  176.                     }  
  177.   
  178.                     // can't move beyond boundary  
  179.                     if (dx < 0 && dx > -mRightViewWidth) {  
  180.                         mCurrentItemView.scrollTo((int)(-dx), 0);  
  181.                     }  
  182.   
  183.                     return true;  
  184.                 } else {  
  185.                     if (mIsShown) {  
  186.                         System.out.println("3---> hiddenRight");  
  187.                         /** 
  188.                          * 情况三: 
  189.                          * 

     

  190.                          * 一个Item的右边布局已经显示, 
  191.                          * 

     

  192.                          * 这时候上下滚动ListView,那么那个右边布局显示的item隐藏其右边布局 
  193.                          */  
  194.                         hiddenRight(mPreItemView);  
  195.                     }  
  196.                 }  
  197.   
  198.                 break;  
  199.   
  200.             case MotionEvent.ACTION_UP:  
  201.             case MotionEvent.ACTION_CANCEL:  
  202.                 System.out.println("============ACTION_UP");  
  203.                 clearPressedState();  
  204.                 if (mIsShown) {  
  205.                     System.out.println("4---> hiddenRight");  
  206.                     /** 
  207.                      * 情况四: 
  208.                      * 

     

  209.                      * 一个Item的右边布局已经显示, 
  210.                      * 

     

  211.                      * 这时候左右滑动当前一个item,那个右边布局显示的item隐藏其右边布局 
  212.                      */  
  213.                     hiddenRight(mPreItemView);  
  214.                 }  
  215.   
  216.                 if (mIsHorizontal != null && mIsHorizontal) {  
  217.                     if (mFirstX - lastX > mRightViewWidth / 2) {  
  218.                         showRight(mCurrentItemView);  
  219.                     } else {  
  220.                         System.out.println("5---> hiddenRight");  
  221.                         /** 
  222.                          * 情况五: 
  223.                          * 

     

  224.                          * 向右滑动一个item,且滑动的距离超过了右边View的宽度的一半,隐藏之。 
  225.                          */  
  226.                         hiddenRight(mCurrentItemView);  
  227.                     }  
  228.   
  229.                     return true;  
  230.                 }  
  231.   
  232.                 break;  
  233.         }  
  234.   
  235.         return super.onTouchEvent(ev);  
  236.     }  
  237.   
  238.     private void clearPressedState() {  
  239.         // TODO current item is still has background, issue  
  240.         mCurrentItemView.setPressed(false);  
  241.         setPressed(false);  
  242.         refreshDrawableState();  
  243.         // invalidate();  
  244.     }  
  245.   
  246.     private void showRight(View view) {  
  247.         System.out.println("=========showRight");  
  248.   
  249.         Message msg = new MoveHandler().obtainMessage();  
  250.         msg.obj = view;  
  251.         msg.arg1 = view.getScrollX();  
  252.         msg.arg2 = mRightViewWidth;  
  253.         msg.sendToTarget();  
  254.   
  255.         mIsShown = true;  
  256.     }  
  257.   
  258.     private void hiddenRight(View view) {  
  259.         System.out.println("=========hiddenRight");  
  260.         if (mCurrentItemView == null) {  
  261.             return;  
  262.         }  
  263.         Message msg = new MoveHandler().obtainMessage();//  
  264.         msg.obj = view;  
  265.         msg.arg1 = view.getScrollX();  
  266.         msg.arg2 = 0;  
  267.   
  268.         msg.sendToTarget();  
  269.   
  270.         mIsShown = false;  
  271.     }  
  272.   
  273.     /** 
  274.      * show or hide right layout animation 
  275.      */  
  276.     @SuppressLint("HandlerLeak")  
  277.     class MoveHandler extends Handler {  
  278.         int stepX = 0;  
  279.   
  280.         int fromX;  
  281.   
  282.         int toX;  
  283.   
  284.         View view;  
  285.   
  286.         private boolean mIsInAnimation = false;  
  287.   
  288.         private void animatioOver() {  
  289.             mIsInAnimation = false;  
  290.             stepX = 0;  
  291.         }  
  292.   
  293.         @Override  
  294.         public void handleMessage(Message msg) {  
  295.             super.handleMessage(msg);  
  296.             if (stepX == 0) {  
  297.                 if (mIsInAnimation) {  
  298.                     return;  
  299.                 }  
  300.                 mIsInAnimation = true;  
  301.                 view = (View)msg.obj;  
  302.                 fromX = msg.arg1;  
  303.                 toX = msg.arg2;  
  304.                 stepX = (int)((toX - fromX) * mDurationStep * 1.0 / mDuration);  
  305.                 if (stepX < 0 && stepX > -1) {  
  306.                     stepX = -1;  
  307.                 } else if (stepX > 0 && stepX < 1) {  
  308.                     stepX = 1;  
  309.                 }  
  310.                 if (Math.abs(toX - fromX) < 10) {  
  311.                     view.scrollTo(toX, 0);  
  312.                     animatioOver();  
  313.                     return;  
  314.                 }  
  315.             }  
  316.   
  317.             fromX += stepX;  
  318.             boolean isLastStep = (stepX > 0 && fromX > toX) || (stepX < 0 && fromX < toX);  
  319.             if (isLastStep) {  
  320.                 fromX = toX;  
  321.             }  
  322.   
  323.             view.scrollTo(fromX, 0);  
  324.             invalidate();  
  325.   
  326.             if (!isLastStep) {  
  327.                 this.sendEmptyMessageDelayed(0, mDurationStep);  
  328.             } else {  
  329.                 animatioOver();  
  330.             }  
  331.         }  
  332.     }  
  333.   
  334.     public int getRightViewWidth() {  
  335.         return mRightViewWidth;  
  336.     }  
  337.   
  338.     public void setRightViewWidth(int mRightViewWidth) {  
  339.         this.mRightViewWidth = mRightViewWidth;  
  340.     }  
  341. }  


github上有另一个项目47deg / android-swipelistview,项目地址:https://github.com/47deg/android-swipelistview,效果如下:





Demo下载地址:http://download.csdn.net/detail/fx_sky/6820665


------------------------------------------------------------

Demo中SwipeAdapter源码中有一处由于粗心写错了,会导致向下滑动时出现数组越界异常,现更正如下:

[java] view plain copy
  1. @Override  
  2.     public int getCount() {  
  3. //      return 100;  
  4.         return data.size();  
  5.     }  





更多相关文章

  1. Android(安卓)显示系统 --- Surface Flinger
  2. [Android]simplelistadapter 与数据库绑定显示list 并且根据数据
  3. android activity 测试
  4. Android用View实现显示中英文混排的文字
  5. android shape标签的使用
  6. Preference 使用方法详解
  7. android MVC中如何在在controller中进行页面跳转(到其他Activity
  8. 安全卫士笔试 第一天
  9. Android(安卓)新控件学习

随机推荐

  1. android组件通讯 Intent Filter隐式实现I
  2. android 使用浏览器打开指定页面
  3. 了解Android误区
  4. Android 文档的阅读顺序!
  5. android 降低Crash率的方案分析和解决思
  6. 【Android(安卓)UI】 Shape详解 (Gradien
  7. Android中如何反编译apk文件
  8. Android当中的防锯齿(Bitmap & Canvas )
  9. 实例16--心理测试
  10. 谈Android模拟点击的价值和实现