Android实现ListView左右滑动删除和编辑

有时候,为了实现项目中的需求,完成设计好的用户交互体验,不的不把这些View重新改造成自己想要的效果。

Android原生的ListView是不支持左右滑动的,但是看到微信电话本上,联系人可以左右滑动进行操作的,就通过自己的设想和思路,并加以实现了。

思路:
1.获取到手指放到屏幕时的x,y位置,并判断点击的处于ListView的那个position。
2.判断滑动的方向,如果是上下方向,touch事件就交给ListView处理;如果是左右方向,就禁止ListView进行滑动。
3.根据手指的移动,来移动选中的View。
4.滑动结束后,把View归位。
5.通过传入的监听器,告诉用户是左滑动还是右滑动。

效果图:

重新的ListView的代码:

package com.example.wz.view;

import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Handler;
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.TextView;

import com.example.wz.R;
import com.example.wz.util.MyLog;
import com.example.wz.util.OpenLooper;
import com.example.wz.util.OpenLooper.LoopCallback;

public class MyListView extends ListView {

 public MyLog log = new MyLog(this, true);

 public float screenWidth;

 public int mTouchSlop;

 public float density;

 public MyListView(Context context) {
  super(context);
 }

 public MyListView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public float transleteSpeed = 2f;
 public OpenLooper openLooper = null;
 public LoopCallback loopCallback = null;

 @SuppressWarnings("deprecation")
 public MyListView(Context context, AttributeSet attrs, int defStyle) {
  super(context, attrs, defStyle);
  this.screenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
  this.mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
  this.density = context.getResources().getDisplayMetrics().density;
  this.openLooper = new OpenLooper();
  this.openLooper.createOpenLooper();
  this.loopCallback = new ListLoopCallback(this.openLooper);
  this.openLooper.loopCallback = this.loopCallback;
 }

 public class BodyStatus {
  public int None = 0, Down = 1, Move = 2, Up = 3, Homing = 4;
  int state = None;
 }

 public BodyStatus bodyStatus = new BodyStatus();

 public class RemoveDirection {
  public int None = 0, Left = 1, Right = 2, Homing_Left = 3, Homing_Right = 4;
  public int state = None;
 }

 public RemoveDirection removeDirection = new RemoveDirection();

 public class ListLoopCallback extends LoopCallback {
  public ListLoopCallback(OpenLooper openLooper) {
   openLooper.super();
  }

  @Override
  public void loop(double ellapsedMillis) {
   if (bodyStatus.state == bodyStatus.Homing) {
    goHoming((float) ellapsedMillis);
   }
  }
 }

 public void goHoming(float delta) {
  float distance = (float) delta * transleteSpeed;
  if (removeDirection.state == removeDirection.Left) {
   float currentX = itemView.getScrollX() + distance;
   if (currentX > screenWidth) {
    distance = distance - (currentX - screenWidth);
   }
   itemView.scrollBy((int) (distance), itemView.getScrollY());
   if (itemView.getScrollX() > screenWidth / 2 + 40 * screenWidth / 1080) {
    t2.setTranslationX(itemView.getScrollX() - screenWidth / 2 - 40 * 3f);
   } else {
    t2.setTranslationX(40 * 3f);
   }
  } else if (removeDirection.state == removeDirection.Right) {
   float currentX = itemView.getScrollX() - distance;
   if (currentX < -screenWidth) {
    distance = distance - (Math.abs(currentX) - screenWidth);
   }
   itemView.scrollBy((int) (-distance), itemView.getScrollY());
   if (itemView.getScrollX() < -(screenWidth / 2 + 40 * 3f * 2)) {
    t1.setTranslationX(-(Math.abs(itemView.getScrollX()) - screenWidth / 2 - 40 * 3f));
   } else {
    t1.setTranslationX(-40 * 3f);
   }
  } else if (removeDirection.state == removeDirection.Homing_Left) {
   float currentX = itemView.getScrollX() - distance;
   if (currentX < 0) {
    distance = distance - (Math.abs(currentX));
   }
   itemView.scrollBy((int) (-distance), itemView.getScrollY());
  } else if (removeDirection.state == removeDirection.Homing_Right) {
   float currentX = itemView.getScrollX() + distance;
   if (currentX > 0) {
    distance = distance - currentX;
   }
   itemView.scrollBy((int) (distance), itemView.getScrollY());
  }
  if (itemView.getScrollX() == 0 || itemView.getScrollX() >= screenWidth || itemView.getScrollX() <= -screenWidth) {
   openLooper.stop();
   if (itemView.getScrollX() >= screenWidth) {
    mRemoveListener.removeItem(removeDirection, position);
   } else if (itemView.getScrollX() <= -screenWidth) {
    mRemoveListener.removeItem(removeDirection, position);
   }
   new Handler().postDelayed(new Runnable() {

    @Override
    public void run() {
     itemView.scrollTo(0, itemView.getScrollY());
     bodyStatus.state = bodyStatus.None;
    }
   }, 300);
  }
 }

 public int touch_down_x;
 public int touch_down_y;

 public View itemView;
 public TextView t1;
 public TextView t2;

 public int SNAP_VELOCITY = 800;
 public int position;

 @Override
 public boolean dispatchTouchEvent(MotionEvent event) {

  int action = event.getAction();

  if (action == MotionEvent.ACTION_DOWN) {
   // addVelocityTracker(event);
   if (bodyStatus.state != bodyStatus.None) {
    return super.dispatchTouchEvent(event);
   }
   this.touch_down_x = (int) event.getX();
   this.touch_down_y = (int) event.getY();

   position = pointToPosition(touch_down_x, touch_down_y);
   if (position == AdapterView.INVALID_POSITION) {
    return super.dispatchTouchEvent(event);
   }
   itemView = getChildAt(position - getFirstVisiblePosition());
   t2 = (TextView) itemView.findViewById(R.id.t2);
   t1 = (TextView) itemView.findViewById(R.id.t1);
  } else if (action == MotionEvent.ACTION_MOVE) {
   if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY || (Math.abs(event.getX() - touch_down_x) > mTouchSlop && Math.abs(event.getY() - touch_down_y) < mTouchSlop)) {
    isSlide = true;
   }
  } else if (action == MotionEvent.ACTION_UP) {
   int velocityX = getScrollVelocity();
   if (Math.abs(velocityX) > SNAP_VELOCITY) {
    if (velocityX > SNAP_VELOCITY) {
     bodyStatus.state = bodyStatus.Homing;
     removeDirection.state = removeDirection.Right;
     openLooper.start();
    } else {
     bodyStatus.state = bodyStatus.Homing;
     removeDirection.state = removeDirection.Left;
     openLooper.start();
    }
   } else {
    if (itemView.getScrollX() >= screenWidth / 2) {
     bodyStatus.state = bodyStatus.Homing;
     removeDirection.state = removeDirection.Left;
     openLooper.start();
    } else if (itemView.getScrollX() <= -screenWidth / 2) {
     bodyStatus.state = bodyStatus.Homing;
     removeDirection.state = removeDirection.Right;
     openLooper.start();
    } else {
     if (itemView.getScrollX() < 0) {
      removeDirection.state = removeDirection.Homing_Right;
     } else {
      removeDirection.state = removeDirection.Homing_Left;
     }
     bodyStatus.state = bodyStatus.Homing;
     openLooper.start();
    }
   }
   recycleVelocityTracker();
   isSlide = false;
  }
  return super.dispatchTouchEvent(event);
 }

 public boolean isSlide = false;

 @SuppressLint("Recycle")
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  if (isSlide && position != AdapterView.INVALID_POSITION) {
   requestDisallowInterceptTouchEvent(true);
   addVelocityTracker(event);
   int x = (int) event.getX();
   int action = event.getAction();
   if (action == MotionEvent.ACTION_DOWN) {
   } else if (action == MotionEvent.ACTION_MOVE) {
    MotionEvent cancelEvent = MotionEvent.obtain(event);
    cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (event.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
    onTouchEvent(cancelEvent);

    int deltaX = touch_down_x - x;
    touch_down_x = x;
    if (itemView.getScrollX() > screenWidth / 2 + 40 * 3f * 2) {
     t2.setTranslationX(itemView.getScrollX() - screenWidth / 2 - 40 * 3f);
    } else {
     t2.setTranslationX(40 * 3f);
    }
    if (itemView.getScrollX() < -(screenWidth / 2 + 40 * 3f * 2)) {
     t1.setTranslationX(-(Math.abs(itemView.getScrollX()) - screenWidth / 2 - 40 * 3f));
    } else {
     t1.setTranslationX(-40 * 3f);
    }
    itemView.scrollBy(deltaX, 0);
    return true;
   }
  }
  return super.onTouchEvent(event);
 }

 public RemoveListener mRemoveListener;

 public void setRemoveListener(RemoveListener removeListener) {
  this.mRemoveListener = removeListener;
 }

 public interface RemoveListener {
  public void removeItem(RemoveDirection direction, int position);
 }

 public VelocityTracker velocityTracker;

 public void addVelocityTracker(MotionEvent event) {
  if (velocityTracker == null) {
   velocityTracker = VelocityTracker.obtain();
  }
  velocityTracker.addMovement(event);
 }

 public int getScrollVelocity() {
  if (velocityTracker != null) {
   velocityTracker.computeCurrentVelocity(1000);
   int velocity = (int) velocityTracker.getXVelocity();
   return velocity;
  }
  return 0;
 }

 public void recycleVelocityTracker() {
  if (velocityTracker != null) {
   velocityTracker.recycle();
   velocityTracker = null;
  }
 }
}

测试ListView的Activity代码:

package com.example.wz;

import java.util.ArrayList;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import com.example.wz.view.MyListView;
import com.example.wz.view.MyListView.RemoveDirection;
import com.example.wz.view.MyListView.RemoveListener;

public class TestListActivity extends Activity {

 LayoutInflater mInflater;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  displayMetrics = new DisplayMetrics();
  this.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_testlist);
  mInflater = getLayoutInflater();
  listView = (MyListView) findViewById(R.id.slideCutListView);
  showAddressDialog();
 }

 public DisplayMetrics displayMetrics;

 MyListView listView;
 public ArrayList<String> items;

 public void showAddressDialog() {
  items = new ArrayList<String>() {
   {
    add("item...1");
    add("item...2");
    add("item...3");
    add("item...4");
    add("item...5");
    add("item...6");
    add("item...7");
    add("item...8");
    add("item...9");
    add("item...10");
    add("item...11");
    add("item...12");
    add("item...13");
    add("item...14");
    add("item...15");
    add("item...16");
    add("item...17");
    add("item...18");
    add("item...19");
    add("item...20");
   }
  };

  NearbyRelationAdapter nearbyRelationAdapter = new NearbyRelationAdapter();
  listView.setAdapter(nearbyRelationAdapter);
  listView.setRemoveListener(new RemoveListener() {

   @Override
   public void removeItem(RemoveDirection direction, int position) {
    if (direction.state == direction.Left) {
     Log.e("A", "left" + "-" + position);
    } else if (direction.state == direction.Right) {
     Log.e("A", "right" + "-" + position);
    }
   }
  });
 }

 public class NearbyRelationAdapter extends BaseAdapter {

  @Override
  public int getCount() {
   return items.size();
  }

  @Override
  public Object getItem(int posotion) {
   return items.get(posotion);
  }

  @Override
  public long getItemId(int posotion) {
   return posotion;
  }

  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
   Holder holder = null;
   if (convertView == null) {
    holder = new Holder();
    convertView = mInflater.inflate(R.layout.view_menu_item1, null);
    holder.title = (TextView) convertView.findViewById(R.id.title);
    holder.o1 = convertView.findViewById(R.id.o1);
    holder.o1.setTranslationX(-displayMetrics.widthPixels);
    holder.o2 = convertView.findViewById(R.id.o2);
    holder.o2.setTranslationX(displayMetrics.widthPixels);
    convertView.setTag(holder);
   } else {
    holder = (Holder) convertView.getTag();
   }
   holder.title.setText(items.get(position));
   convertView.scrollTo(0, convertView.getScrollY());
   return convertView;
  }

  class Holder {
   TextView title;
   View o1, o2;
  }
 }
}

ListView布局文件:

<?xml version="1.0" encoding="utf-8"?>
<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.wz.view.MyListView
  android:id="@+id/slideCutListView"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:cacheColorHint="@android:color/transparent"
  android:listSelector="@android:color/transparent" >
 </com.example.wz.view.MyListView>

 <TextView
  android:layout_width="1dp"
  android:layout_height="match_parent"
  android:layout_centerHorizontal="true"
  android:background="#0099cd" />

</RelativeLayout>

ListView 的Item布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="#fff" >

 <RelativeLayout
  android:id="@+id/o1"
  android:layout_width="match_parent"
  android:layout_height="60dp"
  android:background="#ff0000" >

  <TextView
   android:id="@+id/t1"
   android:layout_width="80dp"
   android:layout_height="wrap_content"
   android:layout_alignParentRight="true"
   android:layout_centerVertical="true"
   android:gravity="center"
   android:padding="10dp"
   android:text="删除"
   android:textColor="#99000000"
   android:textSize="18sp" />
 </RelativeLayout>

 <RelativeLayout
  android:id="@+id/o2"
  android:layout_width="match_parent"
  android:layout_height="60dp"
  android:background="#660099cd" >

  <TextView
   android:id="@+id/t2"
   android:layout_width="80dp"
   android:layout_height="wrap_content"
   android:layout_alignParentLeft="true"
   android:layout_centerVertical="true"
   android:gravity="center"
   android:padding="10dp"
   android:text="编辑"
   android:textColor="#99000000"
   android:textSize="18sp" />
 </RelativeLayout>

 <RelativeLayout
  android:id="@+id/r1"
  android:layout_width="match_parent"
  android:layout_height="60dp"
  android:background="#fff" >

  <TextView
   android:id="@+id/title"
   android:layout_width="match_parent"
   android:layout_height="wrap_content"
   android:layout_centerVertical="true"
   android:gravity="center_vertical"
   android:textColor="#99000000"
   android:textSize="18sp" />
 </RelativeLayout>

</RelativeLayout>

代码中用到的其他的类,在上一篇文章中有: http://www.jb51.net/article/83822.htm

转载来自:http://blog.csdn.net/qxs965266509

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • Android程序开发之ListView 与PopupWindow实现从左向右滑动删除功能

    文章实现的功能是:在ListView的Item上从右向左滑时,出现删除按钮,点击删除按钮把Item删除. 看过文章后,感觉没有必要把dispatchTouchEvent()和onTouchEvent()两个方法都重写,只要重写onTouchEvent就好了.于是对代码作了一些调整: public class MyListView extends ListView { private static final String TAG = "MyListView"; private int

  • Android使用SwipeListView实现类似QQ的滑动删除效果

    QQ的滑动删除效果很不错,要实现这种效果,可以使用SwipeListView. 1. 下载com.fortysevendeg.swipelistview这个项目(以前GitHub上有,现在GitHub上没有了,百度了很多次才下载到的),导入Eclipse,右键单击,选择Properties->Android,选中Library下面的IsLibrary. 2. 新建一个项目MySwipeListView,加入SwipeListView这个库. 3. 在主窗体里面放入一个SwipeListView控

  • android RecyclerView实现条目Item拖拽排序与滑动删除

    效果演示 需求和技术分析 RecyclerView Item拖拽排序::长按RecyclerView的Item或者触摸Item的某个按钮. RecyclerView Item滑动删除:RecyclerView Item滑动删除:RecyclerView的Item滑动删除. 实现方案与技术 利用ItemTouchHelper绑定RecyclerView.ItemTouchHelper.Callback来实现UI更新,并且实现动态控制是否开启拖拽功能和滑动删除功能. 实现步骤 继承抽象类ItemTo

  • Android RecyclerView滑动删除和拖动排序

    本篇是接着上面三篇之后的一个对RecyclerView的介绍,这里多说两句,如果你还在使用ListView的话,可以放弃掉ListView了.RecyclerView自动帮我们缓存Item视图(ViewHolder),允许我们自定义各种动作的动画和分割线,允许我们对Item进行一些手势操作.另外,因为Design库的推出大大方便我们编写带有Material风格的App,而ListView是不兼容这个库的,比如滑动的相互协调,只有RecyclerView能做到. 先看本篇内容的效果图: 效果内容主

  • Android ListView滑动删除操作(SwipeListView)

    新版本的微信和QQ上引入的滑动删除功能是现在比较流行的一个功能.其实这个滑动删除的控件,github上已经有了,是一个热门的开源框架SwipeListView.不过,这个SwipeListView是一个framelayout,即是一个两层的布局,上面的布局front覆盖了下面的布局back,滑动的时候则会滑开front,这样下面的back就显示出来了.但是看了一下微信的滑动删除好像不是这样的,感觉更像是一个超出了屏幕的单层布局,滑动的时候是右边超出屏幕的button进入屏幕,猜测应该不是使用Sw

  • Android仿微信列表滑动删除 如何实现滑动列表SwipeListView

    接上一篇,本篇主要讲如何实现滑动列表SwipeListView. 上篇完成了滑动控件SwipeItemView,这个控件是一个自定义的ViewGroup,作为列表的一个item,为列表提供一些方法让这个SwipeItemView能滑动其视图内容,同时滑动过程中会有顺滑的动画效果.而本篇讲的SwipeListView则是这个列表的具体实现了.当然啦,这个SwipeListView继承自ListView,为了实现我们需要的功能,重点就是重写ListView的onTouchEvent()以及onInt

  • android自定义View滑动删除效果

    View滑动删除效果图 实现功能 1.可以向左滑动,右侧出现删除 2.向左滑动如果删除出现一大半,松手打开删除,反之关闭删除 3.应用场景           微信消息的删除功能 实现原理 1.外面是一个ListView 2.条目是一个自定义控件继承ViewGroup     1).左边一个TextView,右侧屏幕外也有一个TextView     2).所以继承ViewGroup 实现步骤 1.创建一个SlideDeleteView类 1).构造方法要关联 public class Slid

  • android RecyclerView侧滑菜单,滑动删除,长按拖拽,下拉刷新上拉加载

    本文介绍的库中的侧滑效果借鉴自SwipeMenu,并对SipwMenu的源码做了修改与Bug修复,然后才开发出的SwipeRecyclerView. 需要说明的是,本库没有对RecyclerView做大的修改,只是ItemView的封装.看起来是对RecyclerView的修改,其实仅仅是为RecyclerView添加了使用的方法API而已. 本库已经更新了三个版本了,会一直维护下去,根据小伙伴的要求,以后也会添加一些其它功能. SwipeRecyclerView将完美解决这些问题: 以下功能全

  • Android ListView实现上拉加载下拉刷新和滑动删除功能

    最近项目需要用到可以滑动删除并且带有上拉加载下拉刷新的Listview,查阅了一些资料,大多都是在SwipeMenuListView的基础上去添加头部和底部View,来扩展上拉加载和下拉刷新的功能,不过需要手动的去绘制UI及处理一些动画效果.用起来也不是特别方便.刚好项目中用到PulltorefreshLibrary库,就尝试着扩展了一个PullToRefreshSwipeMenuListView类来实现需求.先看一下效果: 实现步骤 一.组合Pulltorefresh与SwipeMenuLis

  • Android中RecyclerView实现滑动删除与拖拽功能

    前言 从Android 5.0开始,谷歌推出了新的控件RecyclerView,相对于早它之前的ListView,优点多多,功能强大,也给我们的开发着提供了极大的便利,今天自己学习一下RecyclerView轻松实现滑动删除及拖拽的效果. 如下图. 相信研究过RecyclerView的同学,应该很清楚该怎么实现这样的效果,若是用ListView,这样的效果实现起来可能就有点麻烦,但是在强大的RecyclerView面前这样的的效果只需很少的代码,因为谷歌给我们提供了强大的工具类ItemTouch

随机推荐