«

带滑动删除的Dummynote

时间:2024-3-2 16:56     作者:韩俊     分类: Html+Css


介绍:首先这个应用是结合了我之前做的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)));
        }

    }

}

标签: javascript html css

热门推荐