带滑动删除的Dummynote

 介绍:首先这个应用是结合了我之前做的Dummynote,那个note的删除主要靠的是长按后的ContextMenu

	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		menu.add(0, MENU_DELETE, 0, "删除记事");
		menu.setHeaderTitle("要如何处理这笔记录?");
		super.onCreateContextMenu(menu, v, menuInfo);
	}

这样做不算差。但是如果可以实现滑动删除的话,效果会更好。于是我借鉴了这篇文章http://blog.csdn.net/xiaanming/article/details/18311877

文章很详细,注释也很多。他一步步告诉你滑动删除具体是怎么实现的。



难点:

问题一、当用户要删除某一行时,我只能得到该行的行号,但不知道该行在数据库中的_id值是多少?

我因此使用了带 limit 和 offest 的语句

db.delete(DATABASE_TABLE,ROWID+"="+rowId,null);
改成了

db.execSQL("delete from tids where _id in(select _id from tids limit 1 offset "+rowId+");"); //是从数据库中的第rowId+1条数据开始查询一条数据,即第rouId+1条

知识:

取前十行

select user_id from udb_user  limit 10; 

跳过前10行,再取前15行

select user_id from udb_user  limit 10,15; 
跳过前15行,再取前10行

select user_id from udb_user  limit 10 offest 15; 





不多说,代码奉上。

Healthyids

package demo.xpf.healthytids;

import android.content.Intent;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.support.v4.widget.SimpleCursorAdapter;
import android.text.StaticLayout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;
import demo.xpf.healthytids.SwipeDismissListView.OnDismissCallback;

public class Healthytids extends Activity {
	private static final String TAG = "tids";
	private SwipeDismissListView swipeDismissListView;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		//getListView().setEmptyView(findViewById(R.id.empty));//设置列表为空时的显示内容为 empty文本框
		setAdapter();
		init();
	}
	
	private TidsDbAdapter mDbHelper ;
	private Cursor mTidCursor;
	
	private void setAdapter(){
		mDbHelper = new TidsDbAdapter(this);
		mDbHelper.open();
		fillData();
	}
	//fillData()刷新数据
	private void fillData(){
		mTidCursor = mDbHelper.getall();
		Log.d(TAG, "filldata  "+mTidCursor);
		startManagingCursor(mTidCursor);
		
		String[] from = new String[]{TidsDbAdapter.NOTE};
		int[] to = new int[]{android.R.id.text1};//android.R.id.text1是Android 框架里面的TextView的一个标识符
		
		//Now create a simple cursor adapter
		SimpleCursorAdapter adapter =
				new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, mTidCursor, from, to);
		swipeDismissListView = (SwipeDismissListView) findViewById(R.id.swipeDismissListView);
		swipeDismissListView.setAdapter(adapter);
	}
	
	
	private void init() {
		swipeDismissListView.setOnDismissCallback(new OnDismissCallback() {
			
			@Override
			public void onDismiss(int dismissPosition) {
				//adapter.remove(adapter.getItem(dismissPosition)); 
				boolean T=mDbHelper.delete(dismissPosition);
				Log.d(TAG, "delete"+dismissPosition+"    "+T);
				fillData();
			}
		});
		
		
		swipeDismissListView.setOnItemClickListener(new OnItemClickListener() {
			private static final int ACTIVITY_EDIT = 0x1001;
			public void onItemClick(AdapterView<?> parent, View view,int position, long id) {
				Intent intent = new Intent(Healthytids.this, NoteEdit.class);
				intent.putExtra(TidsDbAdapter.ROWID, id);//id就是_id值,不是当前的列表项值。代表绑定到这个“ListView”项目的“row ID”
			    startActivityForResult(intent, ACTIVITY_EDIT);	
			}
		});
		
	}
	//Add an entity
		protected static final int MENU_INSERT = Menu.FIRST;		
		@Override
		public boolean onCreateOptionsMenu(Menu menu) {
			// Inflate the menu; this adds items to the action bar if it is present.
			 super.onCreateOptionsMenu(menu);
			 menu.add(0, MENU_INSERT, 0, "新增记事");
			 return super.onCreateOptionsMenu(menu);
		}
		public boolean onOptionsItemSelected(MenuItem item){
			switch(item.getItemId()){
			case MENU_INSERT:
				String noteName = "New Note ";
				mDbHelper.create(noteName);
				fillData();
				return true;
			}
			return super.onOptionsItemSelected(item);
		}

}



SwipeDismissListView

package demo.xpf.healthytids;

import static com.nineoldandroids.view.ViewHelper.setAlpha;
import static com.nineoldandroids.view.ViewHelper.setTranslationX;
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.ViewGroup;
import android.widget.AdapterView;
import android.widget.ListView;

import com.nineoldandroids.animation.Animator;
import com.nineoldandroids.animation.AnimatorListenerAdapter;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.view.ViewHelper;
import com.nineoldandroids.view.ViewPropertyAnimator;
/**
 * @blog http://blog.csdn.net/xiaanming
 * 
 * @author xiaanming
 *
 */
@SuppressWarnings("unused")
public class SwipeDismissListView extends ListView  {
	/**
	 * 认为是用户滑动的最小距离
	 */
	private int mSlop;
	/**
	 * 滑动的最小速度
	 */
	private int mMinFlingVelocity;
	/**
	 * 滑动的最大速度
	 */
	private int mMaxFlingVelocity;
	/**
	 * 执行动画的时间
	 */
	protected long mAnimationTime = 150;
	/**
	 * 用来标记用户是否正在滑动中
	 */
	private boolean mSwiping;
	/**
	 * 滑动速度检测类
	 */
	private VelocityTracker mVelocityTracker;
	/**
	 * 手指按下的position
	 */
	private int mDownPosition;
	/**
	 * 按下的item对应的View
	 */
	private View mDownView;
	private float mDownX;
	private float mDownY;
	/**
	 * item的宽度
	 */
	private int mViewWidth;
	/**
	 * 当ListView的Item滑出界面回调的接口
	 */
	private OnDismissCallback onDismissCallback;

	/**
	 * 设置动画时间
	 * 
	 * @param mAnimationTime
	 */
	public void setmAnimationTime(long mAnimationTime) {
		this.mAnimationTime = mAnimationTime;
	}

	/**
	 * 设置删除回调接口
	 * 
	 * @param onDismissCallback
	 */
	public void setOnDismissCallback(OnDismissCallback onDismissCallback) {
		this.onDismissCallback = onDismissCallback;
	}

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

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

	public SwipeDismissListView(Context context, AttributeSet attrs,
			int defStyle) {
		super(context, attrs, defStyle);

		ViewConfiguration vc = ViewConfiguration.get(context);
		mSlop = vc.getScaledTouchSlop();
		mMinFlingVelocity = vc.getScaledMinimumFlingVelocity() * 8; //获取滑动的最小速度
		mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity();  //获取滑动的最大速度
	}

	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
			handleActionDown(ev);
			break;
		case MotionEvent.ACTION_MOVE:
			return handleActionMove(ev);
		case MotionEvent.ACTION_UP:
			handleActionUp(ev);
			break;
		}
		return super.onTouchEvent(ev);
	}

	/**
	 * 按下事件处理
	 * 
	 * @param ev
	 * @return
	 */
	private void handleActionDown(MotionEvent ev) {
		mDownX = ev.getX();
		mDownY = ev.getY();
		
		mDownPosition = pointToPosition((int) mDownX, (int) mDownY);

		if (mDownPosition == AdapterView.INVALID_POSITION) {
			return;
		}

		mDownView = getChildAt(mDownPosition - getFirstVisiblePosition());

		if (mDownView != null) {
			mViewWidth = mDownView.getWidth();
		}

		//加入速度检测
		mVelocityTracker = VelocityTracker.obtain();
		mVelocityTracker.addMovement(ev);
	}
	

	/**
	 * 处理手指滑动的方法
	 * 
	 * @param ev
	 * @return
	 */
	private boolean handleActionMove(MotionEvent ev) {
		if (mVelocityTracker == null || mDownView == null) {
			return super.onTouchEvent(ev);
		}

		// 获取X方向滑动的距离
		float deltaX = ev.getX() - mDownX;
		float deltaY = ev.getY() - mDownY;

		// X方向滑动的距离大于mSlop并且Y方向滑动的距离小于mSlop,表示可以滑动
		if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < mSlop) {
			mSwiping = true;
			
			//当手指滑动item,取消item的点击事件,不然我们滑动Item也伴随着item点击事件的发生
			MotionEvent cancelEvent = MotionEvent.obtain(ev);
            cancelEvent.setAction(MotionEvent.ACTION_CANCEL |
                       (ev.getActionIndex()<< MotionEvent.ACTION_POINTER_INDEX_SHIFT));
            onTouchEvent(cancelEvent);
		}

		if (mSwiping) {
			// 跟谁手指移动item
			ViewHelper.setTranslationX(mDownView, deltaX);
			// 透明度渐变
			ViewHelper.setAlpha(mDownView, Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX)/ mViewWidth)));

			// 手指滑动的时候,返回true,表示SwipeDismissListView自己处理onTouchEvent,其他的就交给父类来处理
			return true;
		}

		return super.onTouchEvent(ev);

	}

	/**
	 * 手指抬起的事件处理
	 * @param ev
	 */
	private void handleActionUp(MotionEvent ev) {
		if (mVelocityTracker == null || mDownView == null|| !mSwiping) {
			return;
		}

		float deltaX = ev.getX() - mDownX;
		
		//通过滑动的距离计算出X,Y方向的速度
		mVelocityTracker.computeCurrentVelocity(1000);
		float velocityX = Math.abs(mVelocityTracker.getXVelocity());
		float velocityY = Math.abs(mVelocityTracker.getYVelocity());
		
		boolean dismiss = false; //item是否要滑出屏幕
		boolean dismissRight = false;//是否往右边删除
		
		//当拖动item的距离大于item的一半,item滑出屏幕
		if (Math.abs(deltaX) > mViewWidth / 2) {
			dismiss = true;
			dismissRight = deltaX > 0;
			
			//手指在屏幕滑动的速度在某个范围内,也使得item滑出屏幕
		} else if (mMinFlingVelocity <= velocityX
				&& velocityX <= mMaxFlingVelocity && velocityY < velocityX) {
			dismiss = true;
			dismissRight = mVelocityTracker.getXVelocity() > 0;
		}

		if (dismiss) {
			ViewPropertyAnimator.animate(mDownView)
					.translationX(dismissRight ? mViewWidth : -mViewWidth)//X轴方向的移动距离
					.alpha(0)
					.setDuration(mAnimationTime)
					.setListener(new AnimatorListenerAdapter() {
						@Override
						public void onAnimationEnd(Animator animation) {
							//Item滑出界面之后执行删除
							performDismiss(mDownView, mDownPosition);
						}
					});
		} else {
			//将item滑动至开始位置
			ViewPropertyAnimator.animate(mDownView)
			.translationX(0)
			.alpha(1)	
			.setDuration(mAnimationTime).setListener(null);
		}
		
		//移除速度检测
		if(mVelocityTracker != null){
			mVelocityTracker.recycle();
			mVelocityTracker = null;
		}
		
		mSwiping = false;
	}
	

	
	/**
	 * 在此方法中执行item删除之后,其他的item向上或者向下滚动的动画,并且将position回调到方法onDismiss()中
	 * @param dismissView
	 * @param dismissPosition
	 */
	private void performDismiss(final View dismissView, final int dismissPosition) {
		final ViewGroup.LayoutParams lp = dismissView.getLayoutParams();//获取item的布局参数
		final int originalHeight = dismissView.getHeight();//item的高度

		ValueAnimator animator = ValueAnimator.ofInt(originalHeight, 0).setDuration(mAnimationTime);
		animator.start();

		animator.addListener(new AnimatorListenerAdapter() {
			@Override
			public void onAnimationEnd(Animator animation) {
				if (onDismissCallback != null) {
					onDismissCallback.onDismiss(dismissPosition);
				}

				//这段代码很重要,因为我们并没有将item从ListView中移除,而是将item的高度设置为0
				//所以我们在动画执行完毕之后将item设置回来
				ViewHelper.setAlpha(dismissView, 1f);
				ViewHelper.setTranslationX(dismissView, 0);
				ViewGroup.LayoutParams lp = dismissView.getLayoutParams();
				lp.height = originalHeight;
				dismissView.setLayoutParams(lp);

			}
		});

		animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
			@Override
			public void onAnimationUpdate(ValueAnimator valueAnimator) {
				//这段代码的效果是ListView删除某item之后,其他的item向上滑动的效果
				lp.height = (Integer) valueAnimator.getAnimatedValue();
				dismissView.setLayoutParams(lp);
			}
		});

	}

	/**
	 * 删除的回调接口
	 * 
	 * @author xiaanming
	 * 
	 */
	public interface OnDismissCallback {
		public void onDismiss(int dismissPosition);
	}

}


TidsDbAdapter

package demo.xpf.healthytids;

import java.util.Date;

import android.content.ContentValues;
import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.*;
import android.util.Log;
public class TidsDbAdapter {
	private static final String TAG = "tids";
	
	private static final String DATABASE_NAME = "tids.db";
	private static final int DATABASE_VERSION = 1 ;
	private static final String DATABASE_TABLE = "tids";
	private static final String DATABASE_CREATE = 
			"create table tids("
			+"_id INTEGER PRIMARY KEY,"
			+"note TEXT NOT NULL,"
			+"created INTEGER"
			+");";
	
	private static class DatabaseHelper extends SQLiteOpenHelper{
		public DatabaseHelper(Context context) {
			super(context, DATABASE_NAME,null,DATABASE_VERSION);
			// TODO Auto-generated constructor stub
		}

		@Override//创建数据表
		public void onCreate(SQLiteDatabase db) {
			// TODO Auto-generated method stub
			try {
				db.execSQL(DATABASE_CREATE);
				Log.d(TAG, "onCreate !");
			} catch (Exception e) {
				Log.d(TAG, e.toString());
			}
		}

		@Override//更新数据表
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

			try {
				// TODO Auto-generated method stub
				db.execSQL("DROP TABLE IF EXISTS "+DATABASE_TABLE);
				onCreate(db);
				Log.d(TAG, "inUpgrade!");
			} catch (Exception e) {
				Log.d(TAG, "onUpgrade failure!");
			}
		}
}
	
	private Context mCtx = null;	 //抽象界面
	private DatabaseHelper dbHelper; //数据库工具类
	private SQLiteDatabase db;		 //数据库类
	/** COnstructor**/
	public TidsDbAdapter(Context ctx){
		this.mCtx=ctx;
	}
	
	public TidsDbAdapter open () throws SQLException{
		dbHelper = new DatabaseHelper(mCtx);
		db = dbHelper.getWritableDatabase();//数据库不存在就创造一个,若存在就根据版本库来决定是否更新数据库
		
		return this;
	}
	
	public void close(){
		dbHelper.close();
	}
	
	public static final String  ROWID = "_id";
	public static final String  NOTE = "note";
	public static final String  CREATED = "created";
	
	
	//query single entry
		public Cursor get(long rowId)throws SQLException {
			Cursor mCursor = db.query(DATABASE_TABLE,//Which table to select
						new String[]{ROWID,NOTE,CREATED},//Which columns to return
						ROWID+"="+rowId,   //Where clause
						null,   //Where arguments
						null,   //Group By clause
						null,   //Having clause
						null    //Order-by clause
						);
			if(mCursor!=null){
				mCursor.moveToFirst();//指针移到一开始
			}
			return mCursor;
		}
		
		
	//query single entry
	public Cursor getall() {
		return db.query(DATABASE_TABLE,//Which table to select
					new String[]{ROWID,NOTE,CREATED},//Which columns to return
					null,   //Where clause
					null,   //Where arguments
					null,   //Group By clause
					null,   //Having clause
					null    //Order-by clause
					);
	}
	
	//add an entity
	public long create(String Note){
		Date now = new Date();
		ContentValues args = new ContentValues();
		args.put(NOTE, Note);
		args.put(CREATED, now.getDate());
		
		return db.insert(DATABASE_TABLE, null, args);
	}
	
	
	//remove an entity
	public boolean delete(long rowId){
		Log.d(TAG, "delete func"+rowId);
		 db.execSQL("delete from tids where _id in(select _id from tids  limit 1 offset "+rowId+");");
		 //是从数据库中的第rowId+1条数据开始查询一条数据,即第rouId+1条。
		return true;
		 //return db.delete(DATABASE_TABLE,ROWID+"="+rowId,null)>0;//delete失败返回0
	}
	
	
	//update an entity
	public boolean update(long rowId,String note){
		ContentValues args = new ContentValues();
		args.put(NOTE, note);
		
		return db.update(DATABASE_TABLE, args, ROWID+"="+rowId, null)>0;
	}
}


NoteEdit

package demo.xpf.healthytids;

import android.app.Activity;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import demo.xpf.healthytids.TidsDbAdapter;

public class NoteEdit extends Activity{
	private static final String TAG = "tids";
	private TidsDbAdapter mDbHelper;
	private SQLiteDatabase db;	
	@Override
	protected void onCreate(Bundle SavedInstanceState){
		super.onCreate(SavedInstanceState);
		mDbHelper = new TidsDbAdapter(this);
		mDbHelper.open();
		setContentView(R.layout.note_edit);
		Log.d(TAG, "edit");
		findViews();
		showViews(SavedInstanceState);
	}

	private EditText field_note;
	private Button   button_confirm;
	private void findViews() {
		// TODO Auto-generated method stub
		field_note = (EditText) findViewById(R.id.note);
		button_confirm = (Button) findViewById(R.id.confirm);
	}
	
	private Long mRowId;
	private void showViews(Bundle savedInstanceState) {
		mRowId = savedInstanceState != null?
				savedInstanceState.getLong(TidsDbAdapter.ROWID) : null;
		/*saveInstanceState 这个“bundle”数据容器中,取出Activity上一次处于“stop”状态是,键值为“_id”(NotesDbAdapter.ROWID)的内容值。如果这个ACtivity是
		全新打开的或是之前的行程已经被回收了,那么“mRouId”的值被设为“null”*/
				
		if (mRowId == null) {
			Bundle extras = getIntent().getExtras();
			mRowId = extras != null ? extras.getLong(TidsDbAdapter.ROWID) : null;
			Log.d(TAG, "position  "+mRowId);
		/*	
			Cursor mCursor = db.query("tids",new String[]{"_id"}, null, null, null, null, null, mRowId+"1");
			while (mCursor!=null) { 
		          mRowId = mCursor.getLong(0); //获取第一列的值,第一列的索引从0开始 
		          Log.d(TAG, "id  "+mRowId);
		} */
		}
		
		populateFields();//根据RowId查询记录,并显示在EditText中
		
		button_confirm.setOnClickListener(new View.OnClickListener(){
			
			@Override
			public void onClick(View v) {
				mDbHelper.update(mRowId, field_note.getText().toString());
				setResult(RESULT_OK);
				finish();
			}
		});
	}
	
	private void populateFields() {
		if (mRowId != null){
			Cursor note = mDbHelper.get(mRowId);
			startManagingCursor(note);
			
			field_note.setText(note.getString(note.getColumnIndexOrThrow(TidsDbAdapter.NOTE)));
		}
		
	}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值