当前位置: 代码迷 >> Android >> 下拉刷新列表增添SwipeDismissListViewTouchListener实现滑动删除某一列
  详细解决方案

下拉刷新列表增添SwipeDismissListViewTouchListener实现滑动删除某一列

热度:37   发布时间:2016-04-27 22:05:26.0
下拉刷新列表添加SwipeDismissListViewTouchListener实现滑动删除某一列。

《Android SwipeToDismiss:左右滑动删除ListView条目Item》

Android的SwipeToDismiss是github上一个第三方开源框架(github上的项目链接地址:https://github.com/romannurik/Android-SwipeToDismiss )。该开源项目旨在:使得一个ListView的item在用户的手指在屏幕上左滑或者右滑时候,删除当前的这个ListView Item。

 

  1 package com.lixu.SwipeRefreshLayoutyongfa;  2   3 import java.util.ArrayList;  4 import java.util.HashMap;  5   6 import com.lixu.SwipeRefreshLayoutyongfa.SwipeDismissListViewTouchListener.DismissCallbacks;  7 import android.app.Activity;  8 import android.content.Context;  9 import android.os.AsyncTask; 10 import android.os.Bundle; 11 import android.support.v4.widget.SwipeRefreshLayout; 12 import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener; 13 import android.view.LayoutInflater; 14 import android.view.View; 15 import android.view.ViewGroup; 16 import android.widget.ArrayAdapter; 17 import android.widget.ImageView; 18 import android.widget.ListView; 19 import android.widget.TextView; 20  21 public class MainActivity extends Activity { 22     private ArrayAdapter<String> adapter; 23     private ArrayList<HashMap<String, Object>> data; 24     private int count = 0; 25     SwipeRefreshLayout srl; 26     private int[] image = { R.drawable.beijing, R.drawable.chengdu, R.drawable.guangzhou, R.drawable.hangzhou, 27             R.drawable.wuhan, R.drawable.xian, R.drawable.shenzhen }; 28  29     private String[] city = { "北京", "成都", "广州", "杭州", "武汉", "西安", "深圳" }; 30     private String KEY_IMAGE = "image"; 31     private String KEY_TXT = "txt"; 32  33     private int i = 0; 34     private int j = 0; 35  36     ListView lv; 37  38     SwipeDismissListViewTouchListener touchlistener; 39  40     @Override 41     protected void onCreate(Bundle savedInstanceState) { 42         super.onCreate(savedInstanceState); 43         setContentView(R.layout.activity_main); 44  45         data = new ArrayList<HashMap<String, Object>>(); 46  47         lv = (ListView) findViewById(R.id.lv); 48  49         srl = (SwipeRefreshLayout) findViewById(R.id.srl); 50         // 设置刷新动画的颜色. 51         srl.setColorSchemeResources(android.R.color.holo_green_light, android.R.color.holo_blue_bright, 52                 android.R.color.holo_red_light); 53  54         srl.setOnRefreshListener(new OnRefreshListener() { 55             // SwipeRefreshLayout接管其包裹的ListView下拉事件。 56             // 每一次对ListView的下拉动作,将触发SwipeRefreshLayout的onRefresh()。 57             @SuppressWarnings("unchecked") 58             @Override 59             public void onRefresh() { 60  61                 new MyAsyncTask().execute(); 62  63             } 64         }); 65         adapter = new MyAdapter(this, -1); 66  67         lv.setAdapter(adapter); 68         addSwipeDismissListView(); 69         // 往listview里面添加触摸事件 70         lv.setOnTouchListener(touchlistener); 71     } 72  73     private void addSwipeDismissListView() { 74         touchlistener = new SwipeDismissListViewTouchListener(lv, new DismissCallbacks() { 75  76             @Override 77             public void onDismiss(ListView listView, int[] reverseSortedPositions) { 78                 for (int pos : reverseSortedPositions) 79                     // 获取滑动的下标行后删除这一行 80                     data.remove(pos); 81                 // 每次要刷新适配器 82                 adapter.notifyDataSetChanged();
Toast.makeText(getApplicationContext(), "删除成功!", 0).show();
83 } 84 85 @Override 86 public boolean canDismiss(int position) { 87 return true; 88 } 89 }); 90 } 91 92 private class MyAdapter extends ArrayAdapter { 93 private LayoutInflater flater; 94 95 public MyAdapter(Context context, int resource) { 96 super(context, resource); 97 flater = LayoutInflater.from(context); 98 } 99 100 @Override101 public int getCount() {102 return data.size();103 }104 105 @Override106 public View getView(int position, View convertView, ViewGroup parent) {107 if (convertView == null)108 convertView = flater.inflate(R.layout.item, null);109 110 TextView tv = (TextView) convertView.findViewById(R.id.tv);111 tv.setText(data.get(position).get(KEY_TXT) + "");112 113 ImageView iv = (ImageView) convertView.findViewById(R.id.iv);114 iv.setImageResource((Integer) data.get(position).get(KEY_IMAGE));115 116 return convertView;117 }118 }119 120 @SuppressWarnings("rawtypes")121 private class MyAsyncTask extends AsyncTask {122 private HashMap<String, Object> map;123 124 @Override125 protected void onPreExecute() {126 // 刷新开始127 srl.setRefreshing(true);128 map = new HashMap<String, Object>();129 }130 131 @Override132 protected Object doInBackground(Object... params) {133 // 防止下标越界,到达数组长度后返回开始134 if (i == image.length)135 i = 0;136 if (j == city.length)137 j = 0;138 139 map.put(KEY_IMAGE, image[i++]);140 map.put(KEY_TXT, city[j++]);141 142 // 处理一些耗时的事件143 return map;144 }145 146 @SuppressWarnings("unchecked")147 @Override148 protected void onPostExecute(Object result) {149 // 每次从头部添加150 data.add(0, (HashMap<String, Object>) result);151 // 刷新适配器152 adapter.notifyDataSetChanged();153 // 刷新完毕154 srl.setRefreshing(false);155 }156 157 }158 159 }

需要用的SwipeDismissListViewTouchListener类

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


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     tools:context="com.lixu.SwipeRefreshLayoutyongfa.MainActivity" > 6  7     <android.support.v4.widget.SwipeRefreshLayout 8         android:id="@+id/srl" 9         android:layout_width="match_parent"10         android:layout_height="match_parent" >11 12         <ListView13             android:id="@+id/lv"14             android:layout_width="match_parent"15             android:layout_height="match_parent" />16     </android.support.v4.widget.SwipeRefreshLayout>17 18 </RelativeLayout>
 1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3     android:layout_width="match_parent" 4     android:layout_height="match_parent" 5     android:orientation="vertical" > 6  7     <ImageView 8         android:id="@+id/iv" 9         android:layout_width="50dp"10         android:layout_height="50dp" />11 12     <TextView13         android:id="@+id/tv"14         android:layout_width="wrap_content"15         android:layout_height="wrap_content"16         android:textSize="25sp" />17 18 </LinearLayout>

运行效果图:

 

  相关解决方案