• 下拉刷新列表添加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 @Override 101 public int getCount() { 102 return data.size(); 103 } 104 105 @Override 106 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 @Override 125 protected void onPreExecute() { 126 // 刷新开始 127 srl.setRefreshing(true); 128 map = new HashMap<String, Object>(); 129 } 130 131 @Override 132 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 @Override 148 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 list
    112      * 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 one
    122          * or more list item positions.
    123          *
    124          * @param listView
    125          *            The originating {@link ListView}.
    126          * @param reverseSortedPositions
    127          *            An array of positions to dismiss, sorted in descending
    128          *            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 listView
    137      *            The list view whose items should be dismissable.
    138      * @param callbacks
    139      *            The callback to trigger when the user has indicated that she
    140      *            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-dismiss
    156      * gestures.
    157      *
    158      * @param enabled
    159      *            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 the
    167      * {@link ListView} using
    168      * {@link ListView#setOnScrollListener(AbsListView.OnScrollListener)}. If a
    169      * scroll listener is already assigned, the caller should still pass scroll
    170      * changes through to this listener. This will ensure that this
    171      * {@link SwipeDismissListViewTouchListener} is paused during list view
    172      * scrolling.</p>
    173      *
    174      * @see SwipeDismissListViewTouchListener
    175      */
    176     public AbsListView.OnScrollListener makeScrollListener() {
    177         return new AbsListView.OnScrollListener() {
    178             @Override
    179             public void onScrollStateChanged(AbsListView absListView,
    180                     int scrollState) {
    181                 setEnabled(scrollState != AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL);
    182             }
    183 
    184             @Override
    185             public void onScroll(AbsListView absListView, int i, int i1, int i2) {
    186             }
    187         };
    188     }
    189 
    190     @Override
    191     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 flag
    203 
    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                 // cancel
    242                 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 <= absVelocityX
    272                     && absVelocityX <= mMaxFlingVelocity
    273                     && absVelocityY < absVelocityX && mSwiping) {
    274                 // dismiss only if flinging in the same direction as dragging
    275                 dismiss = (velocityX < 0) == (deltaX < 0);
    276                 dismissRight = mVelocityTracker.getXVelocity() > 0;
    277             }
    278             if (dismiss && mDownPosition != ListView.INVALID_POSITION) {
    279                 // dismiss
    280                 final View downView = mDownView; // mDownView gets null'd before
    281                                                     // animation ends
    282                 final int downPosition = mDownPosition;
    283                 ++mDismissAnimationRefCount;
    284                 mDownView.animate()
    285                         .translationX(dismissRight ? mViewWidth : -mViewWidth)
    286                         .alpha(0).setDuration(mAnimationTime)
    287                         .setListener(new AnimatorListenerAdapter() {
    288                             @Override
    289                             public void onAnimationEnd(Animator animation) {
    290                                 performDismiss(downView, downPosition);
    291                             }
    292                         });
    293             } else {
    294                 // cancel
    295                 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) > mSlop
    317                     && 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                 cancelEvent
    325                         .setAction(MotionEvent.ACTION_CANCEL
    326                                 | (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         @Override
    353         public int compareTo(PendingDismissData other) {
    354             // Sort by descending position
    355             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 dismiss
    362         // callback when
    363         // all dismissed list item animations have completed. This triggers
    364         // layout on each animation
    365         // frame; in the future we may want to do something smarter and more
    366         // 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             @Override
    376             public void onAnimationEnd(Animator animation) {
    377                 --mDismissAnimationRefCount;
    378                 if (mDismissAnimationRefCount == 0) {
    379                     // No active animations, process all pending dismisses.
    380                     // Sort by descending position
    381                     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 trying
    390                     // to start a dismiss
    391                     // animation with a stale position
    392                     mDownPosition = ListView.INVALID_POSITION;
    393 
    394                     ViewGroup.LayoutParams lp;
    395                     for (PendingDismissData pendingDismiss : mPendingDismisses) {
    396                         // Reset view presentation
    397                         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 event
    405                     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             @Override
    417             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         <ListView
    13             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     <TextView
    13         android:id="@+id/tv"
    14         android:layout_width="wrap_content"
    15         android:layout_height="wrap_content"
    16         android:textSize="25sp" />
    17 
    18 </LinearLayout>

    运行效果图:

  • 相关阅读:
    未让换行符弄错了数据
    REPLICATE
    内存 商业智能
    sql
    PageMethods介绍
    在ASP.NET AJAX中如何判断浏览器及计算其宽高
    用JavaScript实现网页图片等比例缩放
    js技巧收集(200多个)(转自:asp.net中文俱乐部)
    C#调用ORACLE存储过程返回结果集及函数
    Using PageMethods to access Session data
  • 原文地址:https://www.cnblogs.com/labixiaoxin/p/4994642.html
Copyright © 2020-2023  润新知