日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果

發布時間:2024/4/17 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

本文出自xiaanming的博客(http://blog.csdn.net/xiaanming/article/details/17539199

我在上一篇文章中Android 帶你從源碼的角度解析Scroller的滾動實現原理從源碼的角度介紹了Scroller的滾動實現原理,相信大家對Scroller的使用有一定的了解,這篇文章就給大家帶來使用Scroller的小例子,來幫助大家更加熟悉的掌握Scroller的使用,掌握好了Scroller的使用我們就能實現很多滑動的效果。例如側滑菜單,launcher,ListView的下拉刷新等等效果,我今天實現的是ListView的item的左右滑動刪除item的效果,現在很多朋友看到這個效果應該是在Android的通知欄下拉中看到這個滑動刪除的效果吧,我看到這個效果是在我之前的三星手機上左右滑動打電話發短信的效果,感覺很棒,不過現在很多手機聯系人滑動都不是我之前那臺手機的效果啦,網上很多朋友也寫了關于滑動刪除ListView的item的例子,有些是滑動手指離開之后然后給item加向左或者向右的移動動畫,我覺得這樣子的用戶體驗不是很好,所以今天自己也寫了一個關于ListView左右滑動刪除Item的小例子,ListView的item會隨著手指在屏幕上的滑動而滑動,手指離開屏幕的時候item會根據判斷向左或者向右劃出屏幕,就是跟通知欄的效果差不多,接下來就帶大家來實現這個效果。

先說下實現該效果的主要思路

  • 先根據手指觸摸的點來獲取點擊的是ListView的哪一個item
  • 手指在屏幕中滑動我們利用scrollBy()來使該item跟隨手指一起滑動
  • 手指放開的時候,我們判斷手指拖動的距離來判斷item到底是滑出屏幕還是回到開始位置
  • 主要思路就是上面這三步,接下來我們就用代碼來實現吧,首先我們新建一個項目,叫SlideCutListView

    根據需求我們需要自己自定義一個ListView來實現該功能,接下來先貼出代碼再講解具體的實現

    [java]?view plaincopy
  • package?com.example.slidecutlistview;??
  • ??
  • import?android.content.Context;??
  • import?android.util.AttributeSet;??
  • import?android.view.MotionEvent;??
  • import?android.view.VelocityTracker;??
  • import?android.view.View;??
  • import?android.view.ViewConfiguration;??
  • import?android.view.WindowManager;??
  • import?android.widget.AdapterView;??
  • import?android.widget.ListView;??
  • import?android.widget.Scroller;??
  • ??
  • /**?
  • ?*?@blog?http://blog.csdn.net/xiaanming?
  • ?*??
  • ?*?@author?xiaanming?
  • ?*??
  • ?*/??
  • public?class?SlideCutListView?extends?ListView?{??
  • ????/**?
  • ?????*?當前滑動的ListView position?
  • ?????*/??
  • ????private?int?slidePosition;??
  • ????/**?
  • ?????*?手指按下X的坐標?
  • ?????*/??
  • ????private?int?downY;??
  • ????/**?
  • ?????*?手指按下Y的坐標?
  • ?????*/??
  • ????private?int?downX;??
  • ????/**?
  • ?????*?屏幕寬度?
  • ?????*/??
  • ????private?int?screenWidth;??
  • ????/**?
  • ?????*?ListView的item?
  • ?????*/??
  • ????private?View?itemView;??
  • ????/**?
  • ?????*?滑動類?
  • ?????*/??
  • ????private?Scroller?scroller;??
  • ????private?static?final?int?SNAP_VELOCITY?=?600;??
  • ????/**?
  • ?????*?速度追蹤對象?
  • ?????*/??
  • ????private?VelocityTracker?velocityTracker;??
  • ????/**?
  • ?????*?是否響應滑動,默認為不響應?
  • ?????*/??
  • ????private?boolean?isSlide?=?false;??
  • ????/**?
  • ?????*?認為是用戶滑動的最小距離?
  • ?????*/??
  • ????private?int?mTouchSlop;??
  • ????/**?
  • ?????*??移除item后的回調接口?
  • ?????*/??
  • ????private?RemoveListener?mRemoveListener;??
  • ????/**?
  • ?????*?用來指示item滑出屏幕的方向,向左或者向右,用一個枚舉值來標記?
  • ?????*/??
  • ????private?RemoveDirection?removeDirection;??
  • ??
  • ????//?滑動刪除方向的枚舉值??
  • ????public?enum?RemoveDirection?{??
  • ????????RIGHT,?LEFT;??
  • ????}??
  • ??
  • ??
  • ????public?SlideCutListView(Context?context)?{??
  • ????????this(context,?null);??
  • ????}??
  • ??
  • ????public?SlideCutListView(Context?context,?AttributeSet?attrs)?{??
  • ????????this(context,?attrs,?0);??
  • ????}??
  • ??
  • ????public?SlideCutListView(Context?context,?AttributeSet?attrs,?int?defStyle)?{??
  • ????????super(context,?attrs,?defStyle);??
  • ????????screenWidth?=?((WindowManager)?context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();??
  • ????????scroller?=?new?Scroller(context);??
  • ????????mTouchSlop?=?ViewConfiguration.get(getContext()).getScaledTouchSlop();??
  • ????}??
  • ??????
  • ????/**?
  • ?????*?設置滑動刪除的回調接口?
  • ?????*?@param?removeListener?
  • ?????*/??
  • ????public?void?setRemoveListener(RemoveListener?removeListener)?{??
  • ????????this.mRemoveListener?=?removeListener;??
  • ????}??
  • ??
  • ????/**?
  • ?????*?分發事件,主要做的是判斷點擊的是那個item,?以及通過postDelayed來設置響應左右滑動事件?
  • ?????*/??
  • ????@Override??
  • ????public?boolean?dispatchTouchEvent(MotionEvent?event)?{??
  • ????????switch?(event.getAction())?{??
  • ????????case?MotionEvent.ACTION_DOWN:?{??
  • ????????????addVelocityTracker(event);??
  • ??
  • ????????????//?假如scroller滾動還沒有結束,我們直接返回??
  • ????????????if?(!scroller.isFinished())?{??
  • ????????????????return?super.dispatchTouchEvent(event);??
  • ????????????}??
  • ????????????downX?=?(int)?event.getX();??
  • ????????????downY?=?(int)?event.getY();??
  • ??
  • ????????????slidePosition?=?pointToPosition(downX,?downY);??
  • ??
  • ????????????//?無效的position,?不做任何處理??
  • ????????????if?(slidePosition?==?AdapterView.INVALID_POSITION)?{??
  • ????????????????return?super.dispatchTouchEvent(event);??
  • ????????????}??
  • ??
  • ????????????//?獲取我們點擊的item?view??
  • ????????????itemView?=?getChildAt(slidePosition?-?getFirstVisiblePosition());??
  • ????????????break;??
  • ????????}??
  • ????????case?MotionEvent.ACTION_MOVE:?{??
  • ????????????if?(Math.abs(getScrollVelocity())?>?SNAP_VELOCITY??
  • ????????????????????||?(Math.abs(event.getX()?-?downX)?>?mTouchSlop?&&?Math??
  • ????????????????????????????.abs(event.getY()?-?downY)?<?mTouchSlop))?{??
  • ????????????????isSlide?=?true;??
  • ??????????????????
  • ????????????}??
  • ????????????break;??
  • ????????}??
  • ????????case?MotionEvent.ACTION_UP:??
  • ????????????recycleVelocityTracker();??
  • ????????????break;??
  • ????????}??
  • ??
  • ????????return?super.dispatchTouchEvent(event);??
  • ????}??
  • ??
  • ????/**?
  • ?????*?往右滑動,getScrollX()返回的是左邊緣的距離,就是以View左邊緣為原點到開始滑動的距離,所以向右邊滑動為負值?
  • ?????*/??
  • ????private?void?scrollRight()?{??
  • ????????removeDirection?=?RemoveDirection.RIGHT;??
  • ????????final?int?delta?=?(screenWidth?+?itemView.getScrollX());??
  • ????????//?調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item??
  • ????????scroller.startScroll(itemView.getScrollX(),?0,?-delta,?0,??
  • ????????????????Math.abs(delta));??
  • ????????postInvalidate();?//?刷新itemView??
  • ????}??
  • ??
  • ????/**?
  • ?????*?向左滑動,根據上面我們知道向左滑動為正值?
  • ?????*/??
  • ????private?void?scrollLeft()?{??
  • ????????removeDirection?=?RemoveDirection.LEFT;??
  • ????????final?int?delta?=?(screenWidth?-?itemView.getScrollX());??
  • ????????//?調用startScroll方法來設置一些滾動的參數,我們在computeScroll()方法中調用scrollTo來滾動item??
  • ????????scroller.startScroll(itemView.getScrollX(),?0,?delta,?0,??
  • ????????????????Math.abs(delta));??
  • ????????postInvalidate();?//?刷新itemView??
  • ????}??
  • ??
  • ????/**?
  • ?????*?根據手指滾動itemView的距離來判斷是滾動到開始位置還是向左或者向右滾動?
  • ?????*/??
  • ????private?void?scrollByDistanceX()?{??
  • ????????//?如果向左滾動的距離大于屏幕的二分之一,就讓其刪除??
  • ????????if?(itemView.getScrollX()?>=?screenWidth?/?2)?{??
  • ????????????scrollLeft();??
  • ????????}?else?if?(itemView.getScrollX()?<=?-screenWidth?/?2)?{??
  • ????????????scrollRight();??
  • ????????}?else?{??
  • ????????????//?滾回到原始位置,為了偷下懶這里是直接調用scrollTo滾動??
  • ????????????itemView.scrollTo(0,?0);??
  • ????????}??
  • ??
  • ????}??
  • ??
  • ????/**?
  • ?????*?處理我們拖動ListView?item的邏輯?
  • ?????*/??
  • ????@Override??
  • ????public?boolean?onTouchEvent(MotionEvent?ev)?{??
  • ????????if?(isSlide?&&?slidePosition?!=?AdapterView.INVALID_POSITION)?{??
  • ????????????requestDisallowInterceptTouchEvent(true);??
  • ????????????addVelocityTracker(ev);??
  • ????????????final?int?action?=?ev.getAction();??
  • ????????????int?x?=?(int)?ev.getX();??
  • ????????????switch?(action)?{??
  • ????????????case?MotionEvent.ACTION_DOWN:??
  • ????????????????break;??
  • ????????????case?MotionEvent.ACTION_MOVE:??
  • ??????????????????
  • ????????????????MotionEvent?cancelEvent?=?MotionEvent.obtain(ev);??
  • ????????????????cancelEvent.setAction(MotionEvent.ACTION_CANCEL?|??
  • ???????????????????????????(ev.getActionIndex()<<?MotionEvent.ACTION_POINTER_INDEX_SHIFT));??
  • ????????????????onTouchEvent(cancelEvent);??
  • ??????????????????
  • ????????????????int?deltaX?=?downX?-?x;??
  • ????????????????downX?=?x;??
  • ??
  • ????????????????//?手指拖動itemView滾動,?deltaX大于0向左滾動,小于0向右滾??
  • ????????????????itemView.scrollBy(deltaX,?0);??
  • ??????????????????
  • ????????????????return?true;??//拖動的時候ListView不滾動??
  • ????????????case?MotionEvent.ACTION_UP:??
  • ????????????????int?velocityX?=?getScrollVelocity();??
  • ????????????????if?(velocityX?>?SNAP_VELOCITY)?{??
  • ????????????????????scrollRight();??
  • ????????????????}?else?if?(velocityX?<?-SNAP_VELOCITY)?{??
  • ????????????????????scrollLeft();??
  • ????????????????}?else?{??
  • ????????????????????scrollByDistanceX();??
  • ????????????????}??
  • ??????????????????
  • ????????????????recycleVelocityTracker();??
  • ????????????????//?手指離開的時候就不響應左右滾動??
  • ????????????????isSlide?=?false;??
  • ????????????????break;??
  • ????????????}??
  • ????????}??
  • ??
  • ????????//否則直接交給ListView來處理onTouchEvent事件??
  • ????????return?super.onTouchEvent(ev);??
  • ????}??
  • ??
  • ????@Override??
  • ????public?void?computeScroll()?{??
  • ????????//?調用startScroll的時候scroller.computeScrollOffset()返回true,??
  • ????????if?(scroller.computeScrollOffset())?{??
  • ????????????//?讓ListView?item根據當前的滾動偏移量進行滾動??
  • ????????????itemView.scrollTo(scroller.getCurrX(),?scroller.getCurrY());??
  • ??????????????
  • ????????????postInvalidate();??
  • ??
  • ????????????//?滾動動畫結束的時候調用回調接口??
  • ????????????if?(scroller.isFinished())?{??
  • ????????????????if?(mRemoveListener?==?null)?{??
  • ????????????????????throw?new?NullPointerException("RemoveListener?is?null,?we?should?called?setRemoveListener()");??
  • ????????????????}??
  • ??????????????????
  • ????????????????itemView.scrollTo(0,?0);??
  • ????????????????mRemoveListener.removeItem(removeDirection,?slidePosition);??
  • ????????????}??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?添加用戶的速度跟蹤器?
  • ?????*??
  • ?????*?@param?event?
  • ?????*/??
  • ????private?void?addVelocityTracker(MotionEvent?event)?{??
  • ????????if?(velocityTracker?==?null)?{??
  • ????????????velocityTracker?=?VelocityTracker.obtain();??
  • ????????}??
  • ??
  • ????????velocityTracker.addMovement(event);??
  • ????}??
  • ??
  • ????/**?
  • ?????*?移除用戶速度跟蹤器?
  • ?????*/??
  • ????private?void?recycleVelocityTracker()?{??
  • ????????if?(velocityTracker?!=?null)?{??
  • ????????????velocityTracker.recycle();??
  • ????????????velocityTracker?=?null;??
  • ????????}??
  • ????}??
  • ??
  • ????/**?
  • ?????*?獲取X方向的滑動速度,大于0向右滑動,反之向左?
  • ?????*??
  • ?????*?@return?
  • ?????*/??
  • ????private?int?getScrollVelocity()?{??
  • ????????velocityTracker.computeCurrentVelocity(1000);??
  • ????????int?velocity?=?(int)?velocityTracker.getXVelocity();??
  • ????????return?velocity;??
  • ????}??
  • ??
  • ????/**?
  • ?????*??
  • ?????*?當ListView?item滑出屏幕,回調這個接口?
  • ?????*?我們需要在回調方法removeItem()中移除該Item,然后刷新ListView?
  • ?????*??
  • ?????*?@author?xiaanming?
  • ?????*?
  • ?????*/??
  • ????public?interface?RemoveListener?{??
  • ????????public?void?removeItem(RemoveDirection?direction,?int?position);??
  • ????}??
  • ??
  • }??
    • 首先我們重寫dispatchTouchEvent()方法,該方法是事件的分發方法,我們在里面只做了一些簡單的步驟,我們按下屏幕的時候,如果某個item正在進行滾動,我們直接交給SlideCutListView的父類處理分發事件,否則根據點擊的X,Y坐標利用pointToPosition(int x, int y)來獲取點擊的是ListView的哪一個position,從而獲取到我們需要滑動的item的View,我們還在該方法加入了滑動速度的檢測,并且在ACTION_MOVE的時候來判斷是否響應item的左右移動,用isSlide來記錄是否響應左右滑動
    • 然后就是重寫onTouchEvent()方法,我們先判斷isSlide為true,并且我們點擊的是ListView上面的有效的position,否則直接交給SlideCutListView的父類也就是ListView來處理,在ACTION_MOVE中調用scrollBy()來移動item,scrollBy()是相對item的上一個位置進行移動的,所以我們每次都要用現在移動的距離減去上一個位置的距離然后賦給scrollBy()方法,這樣子我們就實現了item的平滑移動,當我們將手指抬起的時候,我們先根據手指滑動的速度來確定是item是滑出屏幕還是滑動至原始位置,如果向右的速度大于我們設置的SNAP_VELOCITY,item就調用scrollRight()方法滾出屏幕,如果向左的速度小于-SNAP_VELOCITY,則調用scrollLeft()向左滾出屏幕,如果我們是緩慢的移動item,則調用scrollByDistanceX()方法來判斷是滾到那個位置
    在scrollRight()和scrollLeft()方法中我們使用Scroller類的startScroll()方法先設置滾動的參數,然后調用postInvalidate()來刷新界面,界面刷新就會調用computeScroll()方法,我們在里面處理滾動邏輯就行了,值得一提的是computeScroll()里面的這段代碼 [java]?view plaincopy
  • itemView.scrollTo(0,?0);??
  • 我們需要將該item滾動在(0, 0 )這個點,因為我們只是將ListView的Item滾動出屏幕而已,并沒有將該item移除,而且我們不能手動調用removeView()來從ListView中移除該item,我們只能通過改變ListView的數據,然后通過notifyDataSetChanged()來刷新ListView,所以我們需要將其滾動至(0, 0),這里比較關鍵。

    定義好了我們左右滑動的ListView,接下來就來使用它,布局很簡單,一個RelativeLayout包裹我們自定義的ListView

    [html]?view plaincopy
  • <RelativeLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????xmlns:tools="http://schemas.android.com/tools"??
  • ????android:layout_width="match_parent"??
  • ????android:layout_height="match_parent"??
  • ????android:background="@android:color/darker_gray">??
  • ??
  • ????<com.example.slidecutlistview.SlideCutListView??
  • ????????android:id="@+id/slideCutListView"??
  • ????????android:layout_width="match_parent"??
  • ????????android:layout_height="match_parent"???
  • ????????android:listSelector="@android:color/transparent"??
  • ????????android:divider="@drawable/reader_item_divider"??
  • ????????android:cacheColorHint="@android:color/transparent">??
  • ????</com.example.slidecutlistview.SlideCutListView>??
  • ??
  • </RelativeLayout>??

  • 接下來我們來看看ListView的item的布局

    [html]?view plaincopy
  • <?xml?version="1.0"?encoding="UTF-8"?>??
  • <LinearLayout?xmlns:android="http://schemas.android.com/apk/res/android"??
  • ????android:layout_width="fill_parent"??
  • ????android:layout_height="wrap_content"?>??
  • ??
  • ????<LinearLayout??
  • ????????android:layout_width="fill_parent"??
  • ????????android:layout_height="wrap_content"??
  • ????????android:background="@drawable/friendactivity_comment_detail_list2"?>??
  • ??
  • ????????<TextView??
  • ????????????android:id="@+id/list_item"??
  • ????????????android:layout_width="match_parent"??
  • ????????????android:layout_height="wrap_content"??
  • ????????????android:layout_margin="15dip"?/>??
  • ????</LinearLayout>??
  • ??
  • </LinearLayout>??
  • 還記得我在上一篇文章中提到過調用scrollTo()方法是對里面的子View進行滾動的,而不是對整個布局進行滾動的,所以我們用LinearLayout來套住我們的item的布局,這點需要注意一下,不然滾動的只是TextView。

    主頁面MainActivity里面的代碼比較簡單,里面使用的也是ArrayAdapter,相信大家都能看懂

    [html]?view plaincopy
  • package?com.example.slidecutlistview;??
  • ??
  • import?java.util.ArrayList;??
  • import?java.util.List;??
  • ??
  • import?android.app.Activity;??
  • import?android.os.Bundle;??
  • import?android.view.View;??
  • import?android.widget.AdapterView;??
  • import?android.widget.AdapterView.OnItemClickListener;??
  • import?android.widget.ArrayAdapter;??
  • import?android.widget.Toast;??
  • ??
  • import?com.example.slidecutlistview.SlideCutListView.RemoveDirection;??
  • import?com.example.slidecutlistview.SlideCutListView.RemoveListener;??
  • ??
  • public?class?MainActivity?extends?Activity?implements?RemoveListener{??
  • ????private?SlideCutListView?slideCutListView?;??
  • ????private?ArrayAdapter<String>?adapter;??
  • ????private?List<String>?dataSourceList?=?new?ArrayList<String>();??
  • ??
  • ????@Override??
  • ????protected?void?onCreate(Bundle?savedInstanceState)?{??
  • ????????super.onCreate(savedInstanceState);??
  • ????????setContentView(R.layout.activity_main);??
  • ????????init();??
  • ????}??
  • ??
  • ????private?void?init()?{??
  • ????????slideCutListView?=?(SlideCutListView)?findViewById(R.id.slideCutListView);??
  • ????????slideCutListView.setRemoveListener(this);??
  • ??????????
  • ????????for(int?i=0;?i<20;?i++){??
  • ????????????dataSourceList.add("滑動刪除"?+?i);???
  • ????????}??
  • ??????????
  • ????????adapter?=?new?ArrayAdapter<String>(this,?R.layout.listview_item,?R.id.list_item,?dataSourceList);??
  • ????????slideCutListView.setAdapter(adapter);??
  • ??????????
  • ????????slideCutListView.setOnItemClickListener(new?OnItemClickListener()?{??
  • ??
  • ????????????@Override??
  • ????????????public?void?onItemClick(AdapterView<?>?parent,?View?view,??
  • ????????????????????int?position,?long?id)?{??
  • ????????????????Toast.makeText(MainActivity.this,?dataSourceList.get(position),?Toast.LENGTH_SHORT).show();??
  • ????????????}??
  • ????????});??
  • ????}??
  • ??
  • ??????
  • ????//滑動刪除之后的回調方法??
  • ????@Override??
  • ????public?void?removeItem(RemoveDirection?direction,?int?position)?{??
  • ????????adapter.remove(adapter.getItem(position));??
  • ????????switch?(direction)?{??
  • ????????case?RIGHT:??
  • ????????????Toast.makeText(this,?"向右刪除??"+?position,?Toast.LENGTH_SHORT).show();??
  • ????????????break;??
  • ????????case?LEFT:??
  • ????????????Toast.makeText(this,?"向左刪除??"+?position,?Toast.LENGTH_SHORT).show();??
  • ????????????break;??
  • ??
  • ????????default:??
  • ????????????break;??
  • ????????}??
  • ??????????
  • ????}?????
  • ??
  • ??
  • }??
  • 這里面需要對SlideCutListView設置RemoveListener,然后我們在回調方法removeItem(RemoveDirection direction, int position)中刪除該position的數據,在調用notifyDataSetChanged()刷新ListView,我這里用的是ArrayAdatper,直接調用remove()就可以了。

    所有的代碼就編寫完了,我們來運行下程序看看效果吧


    好了,今天的講解就到此結束了,有疑問的朋友可以在下面留言,我會幫大家解答的。今天是2013年的最后一天,希望大家開開心心度過2013,也開開心心的迎接2014,提前祝大家元旦快樂!

    項目源碼,點擊下載



    總結

    以上是生活随笔為你收集整理的Android 使用Scroller实现绚丽的ListView左右滑动删除Item效果的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。