【安卓笔记】滑动删除示例

本文将使用上篇文章介绍的Scroller类来完成一个比较常见的效果——滑动删除效果。
代码如下:

simpleSwipeListView:

package cn.edu.chd.simpleswipelistview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.Scroller;
/**
 * @author Rowandjj
 *
 *滑动删除示例
 */
public class SimpleSwipeListView extends ListView
{
	private static final String TAG = "SimpleSwipeListView";
	private static final boolean DEBUG = true;
	private Scroller mScroller = null;
	private int mTouchSlop;
	
	/**
	 * 屏幕宽度
	 */
	private int mScreenWidth;
	
	private View targetView;
	
	/**
	 * 当前item的位置
	 */
	private int position;
	
	/**
	 * 手指按下的位置
	 */
	private int downX,downY;
	
	/**
	 * 是否能删除item
	 */
	private boolean canRemove = true;
	
	private boolean isSwipe;
	
	/**
	 * item被删除的回调事件
	 */
	private OnItemRemovedListener mListener;
	public interface OnItemRemovedListener
	{
		public void removeItem(int position);
	}
	
	public void setOnItemRemovedListener(OnItemRemovedListener listener)
	{
		this.mListener = listener;
	}
	
	
	public SimpleSwipeListView(Context context)
	{
		this(context, null);
	}
	public SimpleSwipeListView(Context context, AttributeSet attrs)
	{
		this(context, attrs, 0);
	}
	public SimpleSwipeListView(Context context, AttributeSet attrs,
			int defStyleAttr)
	{
		super(context, attrs, defStyleAttr);
		init(context);
	}
	private void init(Context context)
	{
		mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
		mScreenWidth = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getWidth();
		mScroller = new Scroller(context);
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev)
	{
		
		switch (ev.getAction())
		{
		case MotionEvent.ACTION_DOWN:
			if(!mScroller.isFinished())
				return super.onTouchEvent(ev);
			
			downX = (int) ev.getX();
			downY = (int) ev.getY();
			//根据坐标得到position
			position = pointToPosition(downX, downY);
			if(position == AbsListView.INVALID_POSITION)
				return super.onTouchEvent(ev);
			//根据position得到代表item的view对象
			targetView = getChildAt(position-getFirstVisiblePosition());
			break;
		case MotionEvent.ACTION_MOVE:
			int x = (int) ev.getX();
			int y = (int) ev.getY();
			if(Math.abs(x-downX)>mTouchSlop&&Math.abs(y-downY)<mTouchSlop)
			{
				int deltaX = downX-x;
				downX = x;
				downY = y;
				targetView.scrollBy(deltaX,0);
				isSwipe = true;
			}
			if(isSwipe)//禁止listView滚动
				return true;
			break;
		case MotionEvent.ACTION_UP:
			scrollByOffset();
			isSwipe = false;
			break;
		}
		return super.onTouchEvent(ev);
	}
	
	/**
	 * 根据偏移量判断是向左还是向右滚动
	 */
	private void scrollByOffset()
	{
		int scrollX = targetView.getScrollX();//当前偏移
		if(scrollX > mScreenWidth/3)//应该向左滚
		{
			scrollToLeft(scrollX);
		}else if(scrollX < -mScreenWidth/3)//应该向右滚
		{
			scrollToRight(scrollX);
		}else//滚回原点
		{
			scrollToOrigin(scrollX);
		}
	}
	
	private void scrollToOrigin(int scrollX)
	{
		mScroller.startScroll(scrollX,0,-scrollX,0,Math.abs(scrollX));
		postInvalidate();
		canRemove = false;
	}
	
	/**
	 * 向右滚动
	 */
	private void scrollToRight(int scrollX)
	{
		int deltaX = mScreenWidth+scrollX;
		mScroller.startScroll(scrollX, 0, -deltaX, 0, Math.abs(deltaX));
		invalidate();
		canRemove = true;
	}
	
	/**
	 * 向左滚动
	 */
	private void scrollToLeft(int scrollX)
	{
		int deltaX = mScreenWidth - scrollX;
		mScroller.startScroll(scrollX, 0, deltaX, 0, Math.abs(deltaX));
		invalidate();
		canRemove = true;
	}
	
	@Override
	public void computeScroll()
	{
		if(mScroller != null)
		{
			if(mScroller.computeScrollOffset())
			{
				int currX = mScroller.getCurrX();
				int currY = mScroller.getCurrY();
				targetView.scrollTo(currX,currY);
				postInvalidate();
				
				if(mScroller.isFinished())
				{
					targetView.scrollTo(0, 0);
					if(canRemove)
					{
						if(mListener == null)
							throw new RuntimeException("you must call setOnRemoveItemListener to set a listener");
						if(DEBUG)
							Log.d(TAG,"position:"+position);
						//删除item
						mListener.removeItem(position);
						canRemove = false;
					}
				}
			}
		}
	}
}

布局:
activity_main.xml
<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="#ededed"
    tools:context="cn.edu.chd.simpleswipelistview.MainActivity" >
    <cn.edu.chd.simpleswipelistview.SimpleSwipeListView 
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_marginTop="2dp"
        android:layout_marginBottom="2dp"
        android:layout_height="wrap_content"
        android:listSelector="@android:color/transparent"
        android:cacheColorHint="@android:color/transparent"
        android:divider="@null"
        android:dividerHeight="2dp"
        ></cn.edu.chd.simpleswipelistview.SimpleSwipeListView>
    
</RelativeLayout>
item.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingLeft="3dp"
    android:descendantFocusability="beforeDescendants"
    android:paddingRight="3dp" >
    <!--滚动的是下面的内容-->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="55dp"
        android:background="@drawable/card_background_selector"
        android:gravity="center_vertical|left"
        android:descendantFocusability="afterDescendants"
        android:orientation="vertical" >
        <TextView
            android:id="@+id/tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:textColor="@android:color/black"
            android:textSize="18sp" />
    </LinearLayout>
</FrameLayout>

主界面代码:
package cn.edu.chd.simpleswipelistview;
import java.util.ArrayList;
import java.util.List;
import android.app.Activity;
import android.os.Bundle;
import android.widget.ArrayAdapter;
import cn.edu.chd.simpleswipelistview.SimpleSwipeListView.OnItemRemovedListener;
public class MainActivity extends Activity
{
	private SimpleSwipeListView mListView = null;
	private ArrayAdapter<String> mAdapter = null;
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		mListView = (SimpleSwipeListView) findViewById(R.id.lv);
		final List<String> data = new ArrayList<String>();
		for(int i = 0; i < 20; i++)
		{
			data.add("this is text num"+i);
		}
		mAdapter = new ArrayAdapter<>(this,R.layout.item, R.id.tv, data);
		mListView.setAdapter(mAdapter);
		
		mListView.setOnItemRemovedListener(new OnItemRemovedListener()
		{
			@Override
			public void removeItem(int position)
			{
				//此处并不用调用notifyDataSetChanged,因为remove方法内部调用了
				mAdapter.remove(data.get(position));
			}
		});
	}
}

效果截屏不方便,大家自己看吧。

相信大家结合上篇文章介绍的Scroller理解代码应该很easy。
重点需要注意以下几点:
1.如何根据坐标找到view对象。(pointToPosition和getChildAt方法的使用)
2.Scroller的使用,特别是scrollTo、scrollBy以及computeScroll方法。
3.需要注意如果希望对某个view进行滚动,应该调用其父view的scrollTo、scrollBy方法。
4.处理滑动冲突,横向滑动删除时应避免listView滚动。

github源码:https://github.com/Rowandjj/SimpleSwipeListView



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。