zoukankan      html  css  js  c++  java
  • 左右滑动删除ListView条目Item--第三方开源--SwipeToDismiss

    Android的SwipeToDismiss是github上一个第三方开源框架(github上的项目链接地址:https://github.com/romannurik/Android-SwipeToDismiss )。

    该开源项目旨在:使得一个ListView的item在用户的手指在屏幕上左滑或者右滑时候,删除当前的这个ListView Item。

    下载下来只需找到其中的SwipeDismissListViewTouchListener.java类,复制粘贴到需要的包中:

      1 /*
      2  * Copyright 2013 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.zzw.testswipetodismiss;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.ValueAnimator;
     22 import android.graphics.Rect;
     23 import android.os.SystemClock;
     24 import android.view.MotionEvent;
     25 import android.view.VelocityTracker;
     26 import android.view.View;
     27 import android.view.ViewConfiguration;
     28 import android.view.ViewGroup;
     29 import android.view.ViewPropertyAnimator;
     30 import android.widget.AbsListView;
     31 import android.widget.ListView;
     32 
     33 import java.util.ArrayList;
     34 import java.util.Collections;
     35 import java.util.List;
     36 
     37 /**
     38  * A {@link View.OnTouchListener} that makes the list items in a {@link ListView}
     39  * dismissable. {@link ListView} is given special treatment because by default it handles touches
     40  * for its list items... i.e. it's in charge of drawing the pressed state (the list selector),
     41  * handling list item clicks, etc.
     42  *
     43  * <p>After creating the listener, the caller should also call
     44  * {@link ListView#setOnScrollListener(AbsListView.OnScrollListener)}, passing
     45  * in the scroll listener returned by {@link #makeScrollListener()}. If a scroll listener is
     46  * already assigned, the caller should still pass scroll changes through to this listener. This will
     47  * ensure that this {@link SwipeDismissListViewTouchListener} is paused during list view
     48  * scrolling.</p>
     49  *
     50  * <p>Example usage:</p>
     51  *
     52  * <pre>
     53  * SwipeDismissListViewTouchListener touchListener =
     54  *         new SwipeDismissListViewTouchListener(
     55  *                 listView,
     56  *                 new SwipeDismissListViewTouchListener.OnDismissCallback() {
     57  *                     public void onDismiss(ListView listView, int[] reverseSortedPositions) {
     58  *                         for (int position : reverseSortedPositions) {
     59  *                             adapter.remove(adapter.getItem(position));
     60  *                         }
     61  *                         adapter.notifyDataSetChanged();
     62  *                     }
     63  *                 });
     64  * listView.setOnTouchListener(touchListener);
     65  * listView.setOnScrollListener(touchListener.makeScrollListener());
     66  * </pre>
     67  *
     68  * <p>This class Requires API level 12 or later due to use of {@link
     69  * ViewPropertyAnimator}.</p>
     70  *
     71  * <p>For a generalized {@link View.OnTouchListener} that makes any view dismissable,
     72  * see {@link SwipeDismissTouchListener}.</p>
     73  *
     74  * @see SwipeDismissTouchListener
     75  */
     76 public class SwipeDismissListViewTouchListener implements View.OnTouchListener {
     77     // Cached ViewConfiguration and system-wide constant values
     78     private int mSlop;
     79     private int mMinFlingVelocity;
     80     private int mMaxFlingVelocity;
     81     private long mAnimationTime;
     82 
     83     // Fixed properties
     84     private ListView mListView;
     85     private DismissCallbacks mCallbacks;
     86     private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
     87 
     88     // Transient properties
     89     private List<PendingDismissData> mPendingDismisses = new ArrayList<PendingDismissData>();
     90     private int mDismissAnimationRefCount = 0;
     91     private float mDownX;
     92     private float mDownY;
     93     private boolean mSwiping;
     94     private int mSwipingSlop;
     95     private VelocityTracker mVelocityTracker;
     96     private int mDownPosition;
     97     private View mDownView;
     98     private boolean mPaused;
     99 
    100     /**
    101      * The callback interface used by {@link SwipeDismissListViewTouchListener} to inform its client
    102      * about a successful dismissal of one or more list item positions.
    103      */
    104     public interface DismissCallbacks {
    105         /**
    106          * Called to determine whether the given position can be dismissed.
    107          */
    108         boolean canDismiss(int position);
    109 
    110         /**
    111          * Called when the user has indicated they she would like to dismiss one or more list item
    112          * positions.
    113          *
    114          * @param listView               The originating {@link ListView}.
    115          * @param reverseSortedPositions An array of positions to dismiss, sorted in descending
    116          *                               order for convenience.
    117          */
    118         void onDismiss(ListView listView, int[] reverseSortedPositions);
    119     }
    120 
    121     /**
    122      * Constructs a new swipe-to-dismiss touch listener for the given list view.
    123      *
    124      * @param listView  The list view whose items should be dismissable.
    125      * @param callbacks The callback to trigger when the user has indicated that she would like to
    126      *                  dismiss one or more list items.
    127      */
    128     public SwipeDismissListViewTouchListener(ListView listView, DismissCallbacks callbacks) {
    129         ViewConfiguration vc = ViewConfiguration.get(listView.getContext());
    130         mSlop = vc.getScaledTouchSlop();
    131         mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
    132         mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
    133         mAnimationTime = listView.getContext().getResources().getInteger(
    134                 android.R.integer.config_shortAnimTime);
    135         mListView = listView;
    136         mCallbacks = callbacks;
    137     }
    138 
    139     /**
    140      * Enables or disables (pauses or resumes) watching for swipe-to-dismiss gestures.
    141      *
    142      * @param enabled Whether or not to watch for gestures.
    143      */
    144     public void setEnabled(boolean enabled) {
    145         mPaused = !enabled;
    146     }
    147 
    148     /**
    149      * Returns an {@link AbsListView.OnScrollListener} to be added to the {@link
    150      * ListView} using {@link ListView#setOnScrollListener(AbsListView.OnScrollListener)}.
    151      * If a scroll listener is already assigned, the caller should still pass scroll changes through
    152      * to this listener. This will ensure that this {@link SwipeDismissListViewTouchListener} is
    153      * paused during list view scrolling.</p>
    154      *
    155      * @see SwipeDismissListViewTouchListener
    156      */
    157     public AbsListView.OnScrollListener makeScrollListener() {
    158         return new AbsListView.OnScrollListener() {
    159             @Override
    160             public void onScrollStateChanged(AbsListView absListView, int scrollState) {
    161                 setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
    162             }
    163 
    164             @Override
    165             public void onScroll(AbsListView absListView, int i, int i1, int i2) {
    166             }
    167         };
    168     }
    169 
    170     @Override
    171     public boolean onTouch(View view, MotionEvent motionEvent) {
    172         if (mViewWidth < 2) {
    173             mViewWidth = mListView.getWidth();
    174         }
    175 
    176         switch (motionEvent.getActionMasked()) {
    177             case MotionEvent.ACTION_DOWN: {
    178                 if (mPaused) {
    179                     return false;
    180                 }
    181 
    182                 // TODO: ensure this is a finger, and set a flag
    183 
    184                 // Find the child view that was touched (perform a hit test)
    185                 Rect rect = new Rect();
    186                 int childCount = mListView.getChildCount();
    187                 int[] listViewCoords = new int[2];
    188                 mListView.getLocationOnScreen(listViewCoords);
    189                 int x = (int) motionEvent.getRawX() - listViewCoords[0];
    190                 int y = (int) motionEvent.getRawY() - listViewCoords[1];
    191                 View child;
    192                 for (int i = 0; i < childCount; i++) {
    193                     child = mListView.getChildAt(i);
    194                     child.getHitRect(rect);
    195                     if (rect.contains(x, y)) {
    196                         mDownView = child;
    197                         break;
    198                     }
    199                 }
    200 
    201                 if (mDownView != null) {
    202                     mDownX = motionEvent.getRawX();
    203                     mDownY = motionEvent.getRawY();
    204                     mDownPosition = mListView.getPositionForView(mDownView);
    205                     if (mCallbacks.canDismiss(mDownPosition)) {
    206                         mVelocityTracker = VelocityTracker.obtain();
    207                         mVelocityTracker.addMovement(motionEvent);
    208                     } else {
    209                         mDownView = null;
    210                     }
    211                 }
    212                 return false;
    213             }
    214 
    215             case MotionEvent.ACTION_CANCEL: {
    216                 if (mVelocityTracker == null) {
    217                     break;
    218                 }
    219 
    220                 if (mDownView != null && mSwiping) {
    221                     // cancel
    222                     mDownView.animate()
    223                             .translationX(0)
    224                             .alpha(1)
    225                             .setDuration(mAnimationTime)
    226                             .setListener(null);
    227                 }
    228                 mVelocityTracker.recycle();
    229                 mVelocityTracker = null;
    230                 mDownX = 0;
    231                 mDownY = 0;
    232                 mDownView = null;
    233                 mDownPosition = ListView.INVALID_POSITION;
    234                 mSwiping = false;
    235                 break;
    236             }
    237 
    238             case MotionEvent.ACTION_UP: {
    239                 if (mVelocityTracker == null) {
    240                     break;
    241                 }
    242 
    243                 float deltaX = motionEvent.getRawX() - mDownX;
    244                 mVelocityTracker.addMovement(motionEvent);
    245                 mVelocityTracker.computeCurrentVelocity(1000);
    246                 float velocityX = mVelocityTracker.getXVelocity();
    247                 float absVelocityX = Math.abs(velocityX);
    248                 float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
    249                 boolean dismiss = false;
    250                 boolean dismissRight = false;
    251                 if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
    252                     dismiss = true;
    253                     dismissRight = deltaX > 0;
    254                 } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
    255                         && absVelocityY < absVelocityX && mSwiping) {
    256                     // dismiss only if flinging in the same direction as dragging
    257                     dismiss = (velocityX < 0) == (deltaX < 0);
    258                     dismissRight = mVelocityTracker.getXVelocity() > 0;
    259                 }
    260                 if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
    261                     // dismiss
    262                     final View downView = mDownView; // mDownView gets null'd before animation ends
    263                     final int downPosition = mDownPosition;
    264                     ++mDismissAnimationRefCount;
    265                     mDownView.animate()
    266                             .translationX(dismissRight ? mViewWidth : -mViewWidth)
    267                             .alpha(0)
    268                             .setDuration(mAnimationTime)
    269                             .setListener(new AnimatorListenerAdapter() {
    270                                 @Override
    271                                 public void onAnimationEnd(Animator animation) {
    272                                     performDismiss(downView, downPosition);
    273                                 }
    274                             });
    275                 } else {
    276                     // cancel
    277                     mDownView.animate()
    278                             .translationX(0)
    279                             .alpha(1)
    280                             .setDuration(mAnimationTime)
    281                             .setListener(null);
    282                 }
    283                 mVelocityTracker.recycle();
    284                 mVelocityTracker = null;
    285                 mDownX = 0;
    286                 mDownY = 0;
    287                 mDownView = null;
    288                 mDownPosition = ListView.INVALID_POSITION;
    289                 mSwiping = false;
    290                 break;
    291             }
    292 
    293             case MotionEvent.ACTION_MOVE: {
    294                 if (mVelocityTracker == null || mPaused) {
    295                     break;
    296                 }
    297 
    298                 mVelocityTracker.addMovement(motionEvent);
    299                 float deltaX = motionEvent.getRawX() - mDownX;
    300                 float deltaY = motionEvent.getRawY() - mDownY;
    301                 if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
    302                     mSwiping = true;
    303                     mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
    304                     mListView.requestDisallowInterceptTouchEvent(true);
    305 
    306                     // Cancel ListView's touch (un-highlighting the item)
    307                     MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
    308                     cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
    309                             (motionEvent.getActionIndex()
    310                                     << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
    311                     mListView.onTouchEvent(cancelEvent);
    312                     cancelEvent.recycle();
    313                 }
    314 
    315                 if (mSwiping) {
    316                     mDownView.setTranslationX(deltaX - mSwipingSlop);
    317                     mDownView.setAlpha(Math.max(0f, Math.min(1f,
    318                             1f - 2f * Math.abs(deltaX) / mViewWidth)));
    319                     return true;
    320                 }
    321                 break;
    322             }
    323         }
    324         return false;
    325     }
    326 
    327     class PendingDismissData implements Comparable<PendingDismissData> {
    328         public int position;
    329         public View view;
    330 
    331         public PendingDismissData(int position, View view) {
    332             this.position = position;
    333             this.view = view;
    334         }
    335 
    336         @Override
    337         public int compareTo(PendingDismissData other) {
    338             // Sort by descending position
    339             return other.position - position;
    340         }
    341     }
    342 
    343     private void performDismiss(final View dismissView, final int dismissPosition) {
    344         // Animate the dismissed list item to zero-height and fire the dismiss callback when
    345         // all dismissed list item animations have completed. This triggers layout on each animation
    346         // frame; in the future we may want to do something smarter and more performant.
    347 
    348         final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
    349         final int originalHeight = dismissView.getHeight();
    350 
    351         ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
    352 
    353         animator.addListener(new AnimatorListenerAdapter() {
    354             @Override
    355             public void onAnimationEnd(Animator animation) {
    356                 --mDismissAnimationRefCount;
    357                 if (mDismissAnimationRefCount == 0) {
    358                     // No active animations, process all pending dismisses.
    359                     // Sort by descending position
    360                     Collections.sort(mPendingDismisses);
    361 
    362                     int[] dismissPositions = new int[mPendingDismisses.size()];
    363                     for (int i = mPendingDismisses.size() - 1; i >= 0; i--) {
    364                         dismissPositions[i] = mPendingDismisses.get(i).position;
    365                     }
    366                     mCallbacks.onDismiss(mListView, dismissPositions);
    367                     
    368                     // Reset mDownPosition to avoid MotionEvent.ACTION_UP trying to start a dismiss 
    369                     // animation with a stale position
    370                     mDownPosition = ListView.INVALID_POSITION;
    371 
    372                     ViewGroup.LayoutParams lp;
    373                     for (PendingDismissData pendingDismiss : mPendingDismisses) {
    374                         // Reset view presentation
    375                         pendingDismiss.view.setAlpha(1f);
    376                         pendingDismiss.view.setTranslationX(0);
    377                         lp = pendingDismiss.view.getLayoutParams();
    378                         lp.height = originalHeight;
    379                         pendingDismiss.view.setLayoutParams(lp);
    380                     }
    381 
    382                     // Send a cancel event
    383                     long time = SystemClock.uptimeMillis();
    384                     MotionEvent cancelEvent = MotionEvent.obtain(time, time,
    385                             MotionEvent.ACTION_CANCEL, 0, 0, 0);
    386                     mListView.dispatchTouchEvent(cancelEvent);
    387 
    388                     mPendingDismisses.clear();
    389                 }
    390             }
    391         });
    392 
    393         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    394             @Override
    395             public void onAnimationUpdate(ValueAnimator valueAnimator) {
    396                 lp.height = (Integer) valueAnimator.getAnimatedValue();
    397                 dismissView.setLayoutParams(lp);
    398             }
    399         });
    400 
    401         mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));
    402         animator.start();
    403     }
    404 }
    SwipeDismissListViewTouchListener.java

    下面看测试的代码:

    activity_main.xml:

     1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     2     xmlns:tools="http://schemas.android.com/tools"
     3     android:layout_width="match_parent"
     4     android:layout_height="match_parent" >
     5 
     6     <ListView
     7         android:id="@+id/listView"
     8         android:layout_width="match_parent"
     9         android:layout_height="match_parent" />
    10 
    11 </RelativeLayout>
    activity_main.xml

     MainActivity.java:

     1 package com.zzw.testswipetodismiss;
     2 
     3 import java.util.ArrayList;
     4 
     5 import android.app.Activity;
     6 import android.os.Bundle;
     7 import android.widget.ArrayAdapter;
     8 import android.widget.ListView;
     9 import android.widget.Toast;
    10 
    11 public class MainActivity extends Activity {
    12 
    13     private ListView listView;
    14     private ArrayList<String> datas;
    15     private ArrayAdapter adapter;
    16 
    17     @Override
    18     protected void onCreate(Bundle savedInstanceState) {
    19         super.onCreate(savedInstanceState);
    20         setContentView(R.layout.activity_main);
    21 
    22         datas = new ArrayList<String>();
    23 
    24         // 添加测试数据
    25         for (int i = 0; i <= 50; i++) {
    26             datas.add("测试数据-->" + i);
    27         }
    28 
    29         listView = (ListView) findViewById(R.id.listView);
    30 
    31         adapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, datas);
    32         listView.setAdapter(adapter);
    33 
    34         // 将ListView传递过来。
    35         SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(listView,
    36                 new SwipeDismissListViewTouchListener.DismissCallbacks() {
    37 
    38                     // 此处将执行删除,记得要notifyDataSetChanged()
    39                     @Override
    40                     public void onDismiss(ListView listView, int[] reverseSortedPositions) {
    41                         for (int pos : reverseSortedPositions) {
    42                             datas.remove(pos);
    43                             Toast.makeText(getApplicationContext(), "数据" + pos + "删除成功", 0).show();
    44                         }
    45                         adapter.notifyDataSetChanged();
    46                     }
    47 
    48                     @Override
    49                     public boolean canDismiss(int position) {
    50 
    51                         return true;
    52                     }
    53                 });
    54 
    55         listView.setOnTouchListener(touchListener);
    56     }
    57 
    58 }
  • 相关阅读:
    防火墙基础知识(持续补充更新)
    GNS3配置问题(持续更新)
    vc程序设计--对键盘与鼠标的响应(1)
    VC程序设计--文字输出方法与字体示例
    Excel vlookup筛选两列的重复项
    centos 软件安装包下载网站
    CentOS7 SSH免密码登录
    nmap 端口扫描工具
    win7 能ping通dns, 但无法解析域名
    转 Windws Server 2012 Server Backup(备份与还原)
  • 原文地址:https://www.cnblogs.com/zzw1994/p/4994730.html
Copyright © 2011-2022 走看看