Scroller应用:ListView滑动删除

1、设计思路

Scroller的应用--滑屏实现中使用Scroller实现滑屏效果,这里使用Scroller与ListView实现相似QQ滑动。然后点击删除功能。设计思路是Item使用Scroller实现滑动,ListView依据触摸推断是横向滑动还是竖直滑动。关于点击事件处理思路:对于View的onClick事件跟寻常一样,里面针对OnItemClick做了处理,推断触摸距离来推断。假设小于5的话,在Item的onTouchEvent方法中的MotionEvent.ACTION_UP里面返回false,这样ListView里面的dispatchTouchEvent的super.dispatchTouchEvent(event)就会返回false,依据x,y获取当前position以及点击的view。调用super.performItemClick(view, position, view.getId());来告诉ListView出发onItemClick事件。

2、Item的代码

package com.jwzhangjie.scrollview;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.Scroller;

public class ListItemDelete extends LinearLayout {

	private Scroller mScroller;// 滑动控制
	private float mLastMotionX;// 记住上次触摸屏的位置
	private int deltaX;
	private int back_width;
	private float downX;

	public ListItemDelete(Context context) {
		this(context, null);
	}

	public ListItemDelete(Context context, AttributeSet attrs) {
		super(context, attrs);
		init(context);
	}

	private void init(Context context) {
		mScroller = new Scroller(context);
	}

	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {// 会更新Scroller中的当前x,y位置
			scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
			postInvalidate();
		}
	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int count = getChildCount();
		for (int i = 0; i < count; i++) {
			measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
			if (i == 1) {
				back_width = getChildAt(i).getMeasuredWidth();
			}
		}

	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		float x = event.getX();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			Log.e("test", "item  ACTION_DOWN");
			mLastMotionX = x;
			downX = x;
			break;
		case MotionEvent.ACTION_MOVE:
			Log.e("test", back_width + "  item  ACTION_MOVE  " + getScrollX());
			deltaX = (int) (mLastMotionX - x);
			mLastMotionX = x;
			int scrollx = getScrollX() + deltaX;
			if (scrollx > 0 && scrollx < back_width) {
				scrollBy(deltaX, 0);
			} else if (scrollx > back_width) {
				scrollTo(back_width, 0);
			} else if (scrollx < 0) {
				scrollTo(0, 0);
			}
			break;
		case MotionEvent.ACTION_UP:
			Log.e("test", "item  ACTION_UP");
			int scroll = getScrollX();
			if (scroll > back_width / 2) {
				scrollTo(back_width, 0);
			} else {
				scrollTo(0, 0);
			}
			if (Math.abs(x - downX) < 5) {// 这里依据点击距离来推断是否是itemClick
				return false;
			}
			break;
		case MotionEvent.ACTION_CANCEL:
			scrollTo(0, 0);
			break;
		}
		return true;
	}

	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		int margeLeft = 0;
		int size = getChildCount();
		for (int i = 0; i < size; i++) {
			View view = getChildAt(i);
			if (view.getVisibility() != View.GONE) {
				int childWidth = view.getMeasuredWidth();
				// 将内部子孩子横排排列
				view.layout(margeLeft, 0, margeLeft + childWidth,
						view.getMeasuredHeight());
				margeLeft += childWidth;
			}
		}
	}
}


3、ListView的代码

package com.jwzhangjie.scrollview;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ListView;

public class ScrollListviewDelete extends ListView {

	private float minDis = 10;
	private float mLastMotionX;// 记住上次X触摸屏的位置
	private float mLastMotionY;// 记住上次Y触摸屏的位置
	private boolean isLock = false;

	public ScrollListviewDelete(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	/**
	 * 假设一个ViewGroup的onInterceptTouchEvent()方法返回true。说明Touch事件被截获,
	 * 子View不再接收到Touch事件。而是转向本ViewGroup的
	 * onTouchEvent()方法处理。

从Down開始,之后的Move,Up都会直接在onTouchEvent()方法中处理。 * 先前还在处理touch event的child view将会接收到一个 ACTION_CANCEL。

* 假设onInterceptTouchEvent()返回false。则事件会交给child view处理。

*/ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { if (!isIntercept(ev)) { return false; } return super.onInterceptTouchEvent(ev); } @Override public boolean dispatchTouchEvent(MotionEvent event) { boolean dte = super.dispatchTouchEvent(event); if (MotionEvent.ACTION_UP == event.getAction() && !dte) {//onItemClick int position = pointToPosition((int)event.getX(), (int)event.getY()); View view = getChildAt(position); super.performItemClick(view, position, view.getId()); } return dte; } @Override // 处理点击事件,假设是手势的事件则不作点击事件 普通View public boolean performClick() { return super.performClick(); } @Override // 处理点击事件。假设是手势的事件则不作点击事件 ListView public boolean performItemClick(View view, int position, long id) { return super.performItemClick(view, position, id); } /** * 检測是ListView滑动还是item滑动 isLock 一旦判读是item滑动。则在up之前都是返回false */ private boolean isIntercept(MotionEvent ev) { float x = ev.getX(); float y = ev.getY(); int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_DOWN: Log.e("test", "isIntercept ACTION_DOWN "+isLock); mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: Log.e("test", "isIntercept ACTION_MOVE "+isLock); if (!isLock) { float deltaX = Math.abs(mLastMotionX - x); float deltay = Math.abs(mLastMotionY - y); mLastMotionX = x; mLastMotionY = y; if (deltaX > deltay && deltaX > minDis) { isLock = true; return false; } } else { return false; } break; case MotionEvent.ACTION_UP: Log.e("test", "isIntercept ACTION_UP "+isLock); isLock = false; break; case MotionEvent.ACTION_CANCEL: Log.e("test", "isIntercept ACTION_CANCEL "+isLock); isLock = false; break; } return true; } }



4、Activity代码

package com.jwzhangjie.scrollview;

import java.util.ArrayList;
import java.util.List;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class ScrollerDeleteActivity extends FragmentActivity implements
		OnItemClickListener {

	private Toast mToast;
	private ScrollListviewDelete listviewDelete;
	private DeleteAdapter adapter;
	private String[] datas = { "第一项", "第二项", "第三项", "第四项", "第五项", "第六项", "第七项",
			"第八项", "第九项", "第十项" };
	private List<String> listDatas = new ArrayList<String>();

	@Override
	protected void onCreate(Bundle bundle) {
		super.onCreate(bundle);
		setContentView(R.layout.activity_scroller_delete);
		int len = datas.length;
		for (int i = 0; i < len; i++) {
			listDatas.add(datas[i]);
		}
		listviewDelete = (ScrollListviewDelete) findViewById(android.R.id.list);
		adapter = new DeleteAdapter();
		listviewDelete.setAdapter(adapter);
		listviewDelete.setOnItemClickListener(this);
	}

	class DeleteAdapter extends BaseAdapter {

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

		@Override
		public Object getItem(int position) {
			return listDatas.get(position);
		}

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

		@Override
		public View getView(final int position, View convertView,
				ViewGroup parent) {
			ViewHolder holder;
			if (convertView == null) {
				holder = new ViewHolder();
				convertView = LayoutInflater.from(getApplicationContext())
						.inflate(R.layout.item_delete, null);
				holder.itemData = (TextView) convertView
						.findViewById(R.id.itemData);
				holder.btnDelete = (Button) convertView
						.findViewById(R.id.btnDelete);
				holder.btnNao = (Button) convertView.findViewById(R.id.btnNao);
				convertView.setTag(holder);
			} else {
				holder = (ViewHolder) convertView.getTag();
			}
			holder.btnDelete.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					showInfo("点击删除了");
				}
			});
			holder.itemData.setOnClickListener(new OnClickListener() {

				@Override
				public void onClick(View v) {
					showInfo("点击了数据: " + listDatas.get(position));
				}
			});
			holder.btnNao.setOnClickListener(new OnClickListener() {
				@Override
				public void onClick(View v) {
					showInfo("点击了闹铃");
				}
			});
			holder.itemData.setText(listDatas.get(position));
			return convertView;
		}

		class ViewHolder {
			TextView itemData;
			Button btnDelete;
			Button btnNao;
		}
	}

	@Override
	public void onItemClick(AdapterView<?

> parent, View view, int position, long id) { showInfo("onItemClick : " + position); } public void showInfo(String text) { if (mToast == null) { mToast = Toast.makeText(this, text, Toast.LENGTH_SHORT); } else { mToast.setText(text); mToast.setDuration(Toast.LENGTH_SHORT); } mToast.show(); } }



5、XML代码

<?

xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <com.jwzhangjie.scrollview.ScrollListviewDelete android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout>


<?xml version="1.0" encoding="utf-8"?>
<com.jwzhangjie.scrollview.ListItemDelete xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <LinearLayout
        android:id="@+id/front"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/bg_item_list_8"
        android:gravity="center"
        android:orientation="horizontal" >

        <TextView
            android:id="@+id/itemData"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="測试数据" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:orientation="horizontal" >

        <Button
            android:id="@+id/btnNao"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@drawable/bg_item_list_4"
            android:text="闹铃" />

        <Button
            android:id="@+id/btnDelete"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:background="@drawable/bg_item_list_5"
            android:text="删除" />
    </LinearLayout>

</com.jwzhangjie.scrollview.ListItemDelete>

6、界面效果

不保证上面的代码是最新的。更新代码地址:https://github.com/jwzhangjie/-ScrollerDelete


V1.0版本号:解决提供改动数据多时。item滑动底部数据反复。解决方式:推断是否有滑动的item,假设有则复位

地址:https://github.com/jwzhangjie/-ScrollerDelete  里面有编译好的apk

posted @ 2017-04-25 10:03  lytwajue  阅读(162)  评论(0编辑  收藏  举报