zoukankan      html  css  js  c++  java
  • Android UI--SwipeDismissListView_直接删除

    SwipeDismissTouchListener.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.wzq.swipe2dismiss;
     18 
     19 import android.animation.Animator;
     20 import android.animation.AnimatorListenerAdapter;
     21 import android.animation.ValueAnimator;
     22 import android.app.ListActivity;
     23 import android.app.ListFragment;
     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.widget.AdapterView;
     30 import android.widget.ListView;
     31 
     32 /**
     33  * A {@link View.OnTouchListener} that makes any {@link View} dismissable when the
     34  * user swipes (drags her finger) horizontally across the view.
     35  *
     36  * <p><em>For {@link ListView} list items that don't manage their own touch events
     37  * (i.e. you're using
     38  * {@link ListView#setOnItemClickListener(AdapterView.OnItemClickListener)}
     39  * or an equivalent listener on {@link ListActivity} or
     40  * {@link ListFragment}, use {@link SwipeDismissListViewTouchListener} instead.</em></p>
     41  *
     42  * <p>Example usage:</p>
     43  *
     44  * <pre>
     45  * view.setOnTouchListener(new SwipeDismissTouchListener(
     46  *         view,
     47  *         null, // Optional token/cookie object
     48  *         new SwipeDismissTouchListener.OnDismissCallback() {
     49  *             public void onDismiss(View view, Object token) {
     50  *                 parent.removeView(view);
     51  *             }
     52  *         }));
     53  * </pre>
     54  *
     55  * <p>This class Requires API level 12 or later due to use of {@link
     56  * android.view.ViewPropertyAnimator}.</p>
     57  *
     58  * @see SwipeDismissListViewTouchListener
     59  */
     60 public class SwipeDismissTouchListener implements View.OnTouchListener {
     61     // Cached ViewConfiguration and system-wide constant values
     62     private int mSlop;
     63     private int mMinFlingVelocity;
     64     private int mMaxFlingVelocity;
     65     private long mAnimationTime;
     66 
     67     // Fixed properties
     68     private View mView;
     69     private DismissCallbacks mCallbacks;
     70     private int mViewWidth = 1; // 1 and not 0 to prevent dividing by zero
     71 
     72     // Transient properties
     73     private float mDownX;
     74     private float mDownY;
     75     private boolean mSwiping;
     76     private int mSwipingSlop;
     77     private Object mToken;
     78     private VelocityTracker mVelocityTracker;
     79     private float mTranslationX;
     80 
     81     /**
     82      * The callback interface used by {@link SwipeDismissTouchListener} to inform its client
     83      * about a successful dismissal of the view for which it was created.
     84      */
     85     public interface DismissCallbacks {
     86         /**
     87          * Called to determine whether the view can be dismissed.
     88          */
     89         boolean canDismiss(Object token);
     90 
     91         /**
     92          * Called when the user has indicated they she would like to dismiss the view.
     93          *
     94          * @param view  The originating {@link View} to be dismissed.
     95          * @param token The optional token passed to this object's constructor.
     96          */
     97         void onDismiss(View view, Object token);
     98     }
     99 
    100     /**
    101      * Constructs a new swipe-to-dismiss touch listener for the given view.
    102      *
    103      * @param view     The view to make dismissable.
    104      * @param token    An optional token/cookie object to be passed through to the callback.
    105      * @param callbacks The callback to trigger when the user has indicated that she would like to
    106      *                 dismiss this view.
    107      */
    108     public SwipeDismissTouchListener(View view, Object token, DismissCallbacks callbacks) {
    109         ViewConfiguration vc = ViewConfiguration.get(view.getContext());
    110         mSlop = vc.getScaledTouchSlop();
    111         mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 16;
    112         mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();
    113         mAnimationTime = view.getContext().getResources().getInteger(
    114                 android.R.integer.config_shortAnimTime);
    115         mView = view;
    116         mToken = token;
    117         mCallbacks = callbacks;
    118     }
    119 
    120     @Override
    121     public boolean onTouch(View view, MotionEvent motionEvent) {
    122         // offset because the view is translated during swipe
    123         motionEvent.offsetLocation(mTranslationX, 0);
    124 
    125         if (mViewWidth < 2) {
    126             mViewWidth = mView.getWidth();
    127         }
    128 
    129         switch (motionEvent.getActionMasked()) {
    130             case MotionEvent.ACTION_DOWN: {
    131                 // TODO: ensure this is a finger, and set a flag
    132                 mDownX = motionEvent.getRawX();
    133                 mDownY = motionEvent.getRawY();
    134                 if (mCallbacks.canDismiss(mToken)) {
    135                     mVelocityTracker = VelocityTracker.obtain();
    136                     mVelocityTracker.addMovement(motionEvent);
    137                 }
    138                 return false;
    139             }
    140 
    141             case MotionEvent.ACTION_UP: {
    142                 if (mVelocityTracker == null) {
    143                     break;
    144                 }
    145 
    146                 float deltaX = motionEvent.getRawX() - mDownX;
    147                 mVelocityTracker.addMovement(motionEvent);
    148                 mVelocityTracker.computeCurrentVelocity(1000);
    149                 float velocityX = mVelocityTracker.getXVelocity();
    150                 float absVelocityX = Math.abs(velocityX);
    151                 float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
    152                 boolean dismiss = false;
    153                 boolean dismissRight = false;
    154                 if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
    155                     dismiss = true;
    156                     dismissRight = deltaX > 0;
    157                 } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
    158                         && absVelocityY < absVelocityX
    159                         && absVelocityY < absVelocityX && mSwiping) {
    160                     // dismiss only if flinging in the same direction as dragging
    161                     dismiss = (velocityX < 0) == (deltaX < 0);
    162                     dismissRight = mVelocityTracker.getXVelocity() > 0;
    163                 }
    164                 if (dismiss) {
    165                     // dismiss
    166                     mView.animate()
    167                             .translationX(dismissRight ? mViewWidth : -mViewWidth)
    168                             .alpha(0)
    169                             .setDuration(mAnimationTime)
    170                             .setListener(new AnimatorListenerAdapter() {
    171                                 @Override
    172                                 public void onAnimationEnd(Animator animation) {
    173                                     performDismiss();
    174                                 }
    175                             });
    176                 } else if (mSwiping) {
    177                     // cancel
    178                     mView.animate()
    179                             .translationX(0)
    180                             .alpha(1)
    181                             .setDuration(mAnimationTime)
    182                             .setListener(null);
    183                 }
    184                 mVelocityTracker.recycle();
    185                 mVelocityTracker = null;
    186                 mTranslationX = 0;
    187                 mDownX = 0;
    188                 mDownY = 0;
    189                 mSwiping = false;
    190                 break;
    191             }
    192 
    193             case MotionEvent.ACTION_CANCEL: {
    194                 if (mVelocityTracker == null) {
    195                     break;
    196                 }
    197 
    198                 mView.animate()
    199                         .translationX(0)
    200                         .alpha(1)
    201                         .setDuration(mAnimationTime)
    202                         .setListener(null);
    203                 mVelocityTracker.recycle();
    204                 mVelocityTracker = null;
    205                 mTranslationX = 0;
    206                 mDownX = 0;
    207                 mDownY = 0;
    208                 mSwiping = false;
    209                 break;
    210             }
    211 
    212             case MotionEvent.ACTION_MOVE: {
    213                 if (mVelocityTracker == null) {
    214                     break;
    215                 }
    216 
    217                 mVelocityTracker.addMovement(motionEvent);
    218                 float deltaX = motionEvent.getRawX() - mDownX;
    219                 float deltaY = motionEvent.getRawY() - mDownY;
    220                 if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
    221                     mSwiping = true;
    222                     mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
    223                     mView.getParent().requestDisallowInterceptTouchEvent(true);
    224 
    225                     
    226                     MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
    227                     cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
    228                             (motionEvent.getActionIndex() <<
    229                                     MotionEvent.ACTION_POINTER_INDEX_SHIFT));
    230                     mView.onTouchEvent(cancelEvent);
    231                     cancelEvent.recycle();
    232                 }
    233 
    234                 if (mSwiping) {
    235                     mTranslationX = deltaX;
    236                     mView.setTranslationX(deltaX - mSwipingSlop);
    237                     // TODO: use an ease-out interpolator or such
    238 //                    mView.setAlpha(Math.max(0f, Math.min(1f,1f - 2f * Math.abs(deltaX) / mViewWidth)));
    239                     mView.setAlpha(Math.max(0f, Math.min(1f, 1f - Math.abs(deltaX) * 2f / mViewWidth)));
    240                     return true;
    241                 }
    242                 break;
    243             }
    244         }
    245         return false;
    246     }
    247 
    248     private void performDismiss() {
    249         // Animate the dismissed view to zero-height and then fire the dismiss callback.
    250         // This triggers layout on each animation frame; in the future we may want to do something
    251         // smarter and more performant.
    252 
    253         final ViewGroup.LayoutParams lp = mView.getLayoutParams();
    254         final int originalHeight = mView.getHeight();
    255 
    256         ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
    257 
    258         animator.addListener(new AnimatorListenerAdapter() {
    259             @Override
    260             public void onAnimationEnd(Animator animation) {
    261                 mCallbacks.onDismiss(mView, mToken);
    262                 // Reset view presentation
    263                 mView.setAlpha(1f);
    264                 mView.setTranslationX(0);
    265                 lp.height = originalHeight;
    266                 mView.setLayoutParams(lp);
    267             }
    268         });
    269 
    270         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    271             @Override
    272             public void onAnimationUpdate(ValueAnimator valueAnimator) {
    273                 lp.height = (Integer) valueAnimator.getAnimatedValue();
    274                 mView.setLayoutParams(lp);
    275             }
    276         });
    277 
    278         animator.start();
    279     }
    280 }

    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.wzq.swipe2dismiss;
     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                 //另外一种获取mDownView 的方法,不知是否有效~~
    201 //                int downViewIndex = mListView.pointToPosition((int)motionEvent.getX(),(int)motionEvent.getY());
    202 //                mDownView = mListView.getChildAt(downViewIndex - mListView.getFirstVisiblePosition());
    203 
    204                 if (mDownView != null) {
    205                     mDownX = motionEvent.getRawX();
    206                     mDownY = motionEvent.getRawY();
    207                     mDownPosition = mListView.getPositionForView(mDownView);
    208                     if (mCallbacks.canDismiss(mDownPosition)) {
    209                         mVelocityTracker = VelocityTracker.obtain();
    210                         mVelocityTracker.addMovement(motionEvent);
    211                     } else {
    212                         mDownView = null;
    213                     }
    214                 }
    215                 return false;
    216             }
    217 
    218             case MotionEvent.ACTION_CANCEL: {
    219                 if (mVelocityTracker == null) {
    220                     break;
    221                 }
    222 
    223                 if (mDownView != null && mSwiping) {
    224                     // cancel
    225                     mDownView.animate()
    226                             .translationX(0)
    227                             .alpha(1)
    228                             .setDuration(mAnimationTime)
    229                             .setListener(null);
    230                 }
    231                 mVelocityTracker.recycle();
    232                 mVelocityTracker = null;
    233                 mDownX = 0;
    234                 mDownY = 0;
    235                 mDownView = null;
    236                 mDownPosition = ListView.INVALID_POSITION;
    237                 mSwiping = false;
    238                 break;
    239             }
    240 
    241             case MotionEvent.ACTION_UP: {
    242                 if (mVelocityTracker == null) {
    243                     break;
    244                 }
    245 
    246                 float deltaX = motionEvent.getRawX() - mDownX;
    247                 mVelocityTracker.addMovement(motionEvent);
    248                 mVelocityTracker.computeCurrentVelocity(1000);
    249                 float velocityX = mVelocityTracker.getXVelocity();
    250                 float absVelocityX = Math.abs(velocityX);
    251                 float absVelocityY = Math.abs(mVelocityTracker.getYVelocity());
    252                 boolean dismiss = false;
    253                 boolean dismissRight = false;
    254                 if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) {
    255                     dismiss = true;
    256                     dismissRight = deltaX > 0;
    257                 } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity
    258                         && absVelocityY < absVelocityX && mSwiping) {
    259                     // dismiss only if flinging in the same direction as dragging
    260                     dismiss = (velocityX < 0) == (deltaX < 0);
    261                     dismissRight = mVelocityTracker.getXVelocity() > 0;
    262                 }
    263                 if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
    264                     // dismiss
    265                     final View downView = mDownView; // mDownView gets null'd before animation ends
    266                     final int downPosition = mDownPosition;
    267                     ++mDismissAnimationRefCount;
    268                     mDownView.animate()
    269                             .translationX(dismissRight ? mViewWidth : -mViewWidth)
    270                             .alpha(0)
    271                             .setDuration(mAnimationTime)
    272                             .setListener(new AnimatorListenerAdapter() {
    273                                 @Override
    274                                 public void onAnimationEnd(Animator animation) {
    275                                     performDismiss(downView, downPosition);
    276                                 }
    277                             });
    278                 } else {
    279                     // cancel
    280                     mDownView.animate()
    281                             .translationX(0)
    282                             .alpha(1)
    283                             .setDuration(mAnimationTime)
    284                             .setListener(null);
    285                 }
    286                 mVelocityTracker.recycle();
    287                 mVelocityTracker = null;
    288                 mDownX = 0;
    289                 mDownY = 0;
    290                 mDownView = null;
    291                 mDownPosition = ListView.INVALID_POSITION;
    292                 mSwiping = false;
    293                 break;
    294             }
    295 
    296             case MotionEvent.ACTION_MOVE: {
    297                 if (mVelocityTracker == null || mPaused) {
    298                     break;
    299                 }
    300 
    301                 mVelocityTracker.addMovement(motionEvent);
    302                 float deltaX = motionEvent.getRawX() - mDownX;
    303                 float deltaY = motionEvent.getRawY() - mDownY;
    304                 if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) {
    305                     mSwiping = true;
    306                     mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop);
    307                     mListView.requestDisallowInterceptTouchEvent(true);
    308 
    309                     // Cancel ListView's touch (un-highlighting the item)
    310                     MotionEvent cancelEvent = MotionEvent.obtain(motionEvent);
    311                     cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
    312                             (motionEvent.getActionIndex()
    313                                     << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
    314                     mListView.onTouchEvent(cancelEvent);
    315                     cancelEvent.recycle();
    316                 }
    317 
    318                 if (mSwiping) {
    319                     mDownView.setTranslationX(deltaX - mSwipingSlop);
    320                     mDownView.setAlpha(Math.max(0f, Math.min(1f,
    321                             1f - 2f * Math.abs(deltaX) / mViewWidth)));
    322                     return true;
    323                 }
    324                 break;
    325             }
    326         }
    327         return false;
    328     }
    329 
    330     class PendingDismissData implements Comparable<PendingDismissData> {
    331         public int position;
    332         public View view;
    333 
    334         public PendingDismissData(int position, View view) {
    335             this.position = position;
    336             this.view = view;
    337         }
    338 
    339         @Override
    340         public int compareTo(PendingDismissData other) {
    341             // Sort by descending position
    342             return other.position - position;
    343         }
    344     }
    345 
    346     private void performDismiss(final View dismissView, final int dismissPosition) {
    347         // Animate the dismissed list item to zero-height and fire the dismiss callback when
    348         // all dismissed list item animations have completed. This triggers layout on each animation
    349         // frame; in the future we may want to do something smarter and more performant.
    350 
    351         final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
    352         final int originalHeight = dismissView.getHeight();
    353 
    354         ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 1).setDuration(mAnimationTime);
    355 
    356         animator.addListener(new AnimatorListenerAdapter() {
    357             @Override
    358             public void onAnimationEnd(Animator animation) {
    359                 --mDismissAnimationRefCount;
    360                 if (mDismissAnimationRefCount == 0) {
    361                     // No active animations, process all pending dismisses.
    362                     // Sort by descending position
    363                     Collections.sort(mPendingDismisses);
    364 
    365                     int[] dismissPositions = new int[mPendingDismisses.size()];
    366                     for (int i = mPendingDismisses.size() - 1; i >= 0; i--) {
    367                         dismissPositions[i] = mPendingDismisses.get(i).position;
    368                     }
    369                     mCallbacks.onDismiss(mListView, dismissPositions);
    370                     
    371                     // Reset mDownPosition to avoid MotionEvent.ACTION_UP trying to start a dismiss 
    372                     // animation with a stale position
    373                     mDownPosition = ListView.INVALID_POSITION;
    374 
    375                     ViewGroup.LayoutParams lp;
    376                     for (PendingDismissData pendingDismiss : mPendingDismisses) {
    377                         // Reset view presentation // TODO 
    378                         pendingDismiss.view.setAlpha(1f);
    379                         pendingDismiss.view.setTranslationX(0);
    380                         lp = pendingDismiss.view.getLayoutParams();
    381                         lp.height = originalHeight;
    382                         pendingDismiss.view.setLayoutParams(lp);
    383                     }
    384 
    385                     // Send a cancel event
    386                     long time = SystemClock.uptimeMillis();
    387                     MotionEvent cancelEvent = MotionEvent.obtain(time, time,
    388                             MotionEvent.ACTION_CANCEL, 0, 0, 0);
    389                     mListView.dispatchTouchEvent(cancelEvent);
    390 
    391                     mPendingDismisses.clear();
    392                 }
    393             }
    394         });
    395 
    396         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    397             @Override
    398             public void onAnimationUpdate(ValueAnimator valueAnimator) {
    399                 lp.height = (Integer) valueAnimator.getAnimatedValue();// TODO 
    400                 dismissView.setLayoutParams(lp);
    401             }
    402         });
    403 
    404         mPendingDismisses.add(new PendingDismissData(dismissPosition, dismissView));
    405         animator.start();
    406     }
    407 }

    SwipeDismissActivity.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.wzq.swipe2dismiss;
     18 
     19 import android.app.ListActivity;
     20 import android.os.Bundle;
     21 import android.view.View;
     22 import android.view.ViewGroup;
     23 import android.widget.ArrayAdapter;
     24 import android.widget.Button;
     25 import android.widget.ListView;
     26 import android.widget.Toast;
     27 
     28 import java.util.ArrayList;
     29 import java.util.Arrays;
     30 
     31 import com.example.wzq1412.R;
     32 
     33 public class Swipe2DismissActivity extends ListActivity {
     34     ArrayAdapter<String> mAdapter;
     35 
     36     public void onCreate(Bundle savedInstanceState) {
     37         super.onCreate(savedInstanceState);
     38         setContentView(R.layout.a_swipe2dismiss);
     39 
     40         // Set up ListView example
     41         String[] items = new String[20];
     42         for (int i = 0; i < items.length; i++) {
     43             items[i] = "Item " + (i + 1);
     44         }
     45 
     46         mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
     47                 android.R.id.text1, new ArrayList<String>(Arrays.asList(items)));
     48         setListAdapter(mAdapter);
     49 
     50         ListView listView = getListView();
     51         // Create a ListView-specific touch listener. ListViews are given
     52         // special treatment because
     53         // by default they handle touches for their list items... i.e. they're
     54         // in charge of drawing
     55         // the pressed state (the list selector), handling list item clicks,
     56         // etc.
     57         SwipeDismissListViewTouchListener touchListener = new SwipeDismissListViewTouchListener(
     58                 listView, new SwipeDismissListViewTouchListener.DismissCallbacks() {
     59                     @Override
     60                     public boolean canDismiss(int position) {
     61                         return true;
     62                     }
     63 
     64                     @Override
     65                     public void onDismiss(ListView listView, int[] reverseSortedPositions) {
     66                         // TODO at
     67                         // java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
     68                         if (mAdapter.getCount() == 0) {
     69                             return;
     70                         }
     71                         for (int position : reverseSortedPositions) {
     72                             if (position >= mAdapter.getCount()) {
     73                                 return;
     74                             }
     75                             mAdapter.remove(mAdapter.getItem(position));
     76                         }
     77                         mAdapter.notifyDataSetChanged();
     78                     }
     79                 });
     80         listView.setOnTouchListener(touchListener);
     81         // Setting this scroll listener is required to ensure that during
     82         // ListView scrolling,
     83         // we don't look for swipes.
     84         listView.setOnScrollListener(touchListener.makeScrollListener());
     85 
     86         // Set up normal ViewGroup example
     87         final ViewGroup dismissableContainer = (ViewGroup) findViewById(R.id.dismissable_container);
     88         for (int i = 0; i < items.length; i++) {
     89             final Button dismissableButton = new Button(this);
     90             dismissableButton.setLayoutParams(new ViewGroup.LayoutParams(
     91                     ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
     92             dismissableButton.setText("Button " + (i + 1));
     93             dismissableButton.setOnClickListener(new View.OnClickListener() {
     94                 @Override
     95                 public void onClick(View view) {
     96                     Toast.makeText(Swipe2DismissActivity.this,
     97                             "Clicked " + ((Button) view).getText(), Toast.LENGTH_SHORT).show();
     98                 }
     99             });
    100             // Create a generic swipe-to-dismiss touch listener.
    101             dismissableButton.setOnTouchListener(new SwipeDismissTouchListener(dismissableButton,
    102                     null, new SwipeDismissTouchListener.DismissCallbacks() {
    103                         @Override
    104                         public boolean canDismiss(Object token) {
    105                             return true;
    106                         }
    107 
    108                         @Override
    109                         public void onDismiss(View view, Object token) {
    110                             dismissableContainer.removeView(dismissableButton);
    111                         }
    112                     }));
    113             dismissableContainer.addView(dismissableButton);
    114         }
    115     }
    116 
    117     @Override
    118     protected void onListItemClick(ListView listView, View view, int position, long id) {
    119         Toast.makeText(this, "Clicked " + getListAdapter().getItem(position).toString(),
    120                 Toast.LENGTH_SHORT).show();
    121     }
    122 }

    a_swipe2dismiss.xml

     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 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    18     android:layout_width="match_parent"
    19     android:layout_height="match_parent"
    20     android:orientation="horizontal"
    21     android:baselineAligned="false"
    22     android:padding="16dp">
    23 
    24     <LinearLayout android:layout_width="0dp"
    25         android:layout_weight="1"
    26         android:layout_height="match_parent"
    27         android:layout_marginRight="8dp"
    28         android:orientation="vertical">
    29 
    30         <TextView android:layout_width="match_parent"
    31             android:layout_height="wrap_content"
    32             style="?android:listSeparatorTextViewStyle"
    33             android:text="Simple Views" />
    34 
    35         <ScrollView android:fillViewport="true"
    36             android:layout_width="match_parent"
    37             android:layout_weight="1"
    38             android:layout_height="0dp">
    39             <LinearLayout android:id="@+id/dismissable_container"
    40                 android:layout_width="match_parent"
    41                 android:layout_height="wrap_content"
    42                 android:orientation="vertical" />
    43         </ScrollView>
    44 
    45     </LinearLayout>
    46 
    47     <LinearLayout android:layout_width="0dp"
    48         android:layout_weight="1"
    49         android:layout_height="match_parent"
    50         android:layout_marginLeft="8dp"
    51         android:orientation="vertical">
    52 
    53         <TextView android:layout_width="match_parent"
    54             android:layout_height="wrap_content"
    55             style="?android:listSeparatorTextViewStyle"
    56             android:text="ListView" />
    57 
    58         <ListView
    59             android:id="@android:id/list"
    60             android:layout_weight="1"
    61             android:layout_width="match_parent"
    62             android:layout_height="0dp" />
    63     </LinearLayout>
    64 </LinearLayout>
  • 相关阅读:
    Eclipse下进行SVN提交时报“svn: Transaction is out of date
    【Spring学习】Spring事物管理之aop技术
    【框架学习】ibatis DAO框架分析
    【maven详解-插件】maven 插件机制
    【maven详解-插件】maven插件学习之maven-source-plugin
    关于使用 no-js (Modernizr)
    白话讲MyIsam和InnoDB的区别
    向鼠标右键菜单增加菜单项
    表单提交按钮input和button、a的差异
    MySQL数据库索引的设计原则
  • 原文地址:https://www.cnblogs.com/wangziqiang/p/4218978.html
Copyright © 2011-2022 走看看