Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> 左右滑動刪除ListView條目Item--第三方開源--SwipeToDismiss,第三方listview

左右滑動刪除ListView條目Item--第三方開源--SwipeToDismiss,第三方listview

編輯:關於android開發

左右滑動刪除ListView條目Item--第三方開源--SwipeToDismiss,第三方listview


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 }

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved