自定义listView添加滑动删除功能
今天研究了一下android里面的手势,结合昨天学习的自定义View,做了一个自定义的listview,继承自listView,添加了条目的滑动手势操作,滑动后出现一个删除按钮,点击删除按钮,触发一个删除的事件,在事件中进行删除当选行的元素,刷新listview。
一共分为以下几步进行:
1、新建一个按钮的布局文件,用来作为动态添加的按钮:layout_button.xml
- <?xml version="1.0" encoding="utf-8"?>
- <Button
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:text="删除"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/btn1"/>
2、定义按钮显示,隐藏的动画效果,简单的缩放动画:
btn_hide.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <scale xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromXScale="1.0"
- android:toXScale="0"
- android:fromYScale="1.0"
- android:toYScale="1.0"
- android:pivotX="100%"
- android:pivotY="0"
- android:duration="200"
- />
btn_show.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <scale xmlns:android="http://schemas.android.com/apk/res/android"
- android:fromXScale="0"
- android:toXScale="1.0"
- android:fromYScale="1.0"
- android:toYScale="1.0"
- android:pivotX="100%"
- android:pivotY="0"
- android:duration="200"
- />
3、自定义ListView,继承自listView,并实现OnTouchListener,OnGestureListener接口,代码就不一步一步写了,里面我尽可能的注释详细一些:MyListView.java
- package com.example.viewtest;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.GestureDetector;
- import android.view.GestureDetector.OnGestureListener;
- import android.view.LayoutInflater;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.View.OnTouchListener;
- import android.view.ViewGroup;
- import android.view.animation.AnimationUtils;
- import android.widget.ListView;
- import android.widget.RelativeLayout;
- /**
- * 项目名称:viewTest
- * 实现功能: 自定义ListView,增加滑动删除功能
- * 类名称:MyListView
- * 类描述:(该类的主要功能)
- * 创建人:徐纪伟
- * E-mail: xujiwei558@126.com
- * 创建时间:2014年11月2日 下午3:37:40
- * 修改人:
- * 修改时间:
- * 修改备注:
- * @version
- */
- public class MyListView extends ListView implements OnTouchListener,OnGestureListener {
- /**
- * 手势识别类
- */
- private GestureDetector gestureDetector;
- /**
- * 滑动时出现的按钮
- */
- private View btnDelete;
- /**
- * listview的每一个item的布局
- */
- private ViewGroup viewGroup;
- /**
- * 选中的项
- */
- private int selectedItem;
- /**
- * 是否已经显示删除按钮
- */
- private boolean isDeleteShow;
- /**
- * 点击删除按钮时删除每一行的事件监听器
- */
- private OnItemDeleteListener onItemDeleteListener;
- /**
- * 构造函数,初始化手势监听器等
- * @param context
- * @param attrs
- */
- public MyListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- gestureDetector = new GestureDetector(getContext(),this);
- setOnTouchListener(this);
- }
- public void setOnItemDeleteListener(OnItemDeleteListener onItemDeleteListener) {
- this.onItemDeleteListener = onItemDeleteListener;
- }
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- //得到当前触摸的条目
- selectedItem = pointToPosition((int)event.getX(), (int)event.getY());
- //如果删除按钮已经显示,那么隐藏按钮,异常按钮在当前位置的绘制
- if (isDeleteShow) {
- btnHide(btnDelete);
- viewGroup.removeView(btnDelete);
- btnDelete = null;
- isDeleteShow = false;
- return false;
- }else{
- //如果按钮没显示,则触发手势事件
- //由此去触发GestureDetector的事件,可以查看其源码得知,onTouchEvent中进行了手势判断,调用onFling
- return gestureDetector.onTouchEvent(event);
- }
- }
- @Override
- public boolean onDown(MotionEvent e) {
- //得到当前触摸的条目
- if (!isDeleteShow) {
- selectedItem = pointToPosition((int)e.getX(), (int)e.getY());
- }
- return true;
- }
- @Override
- public void onShowPress(MotionEvent e) {
- }
- @Override
- public boolean onSingleTapUp(MotionEvent e) {
- return false;
- }
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- return false;
- }
- @Override
- public void onLongPress(MotionEvent e) {
- }
- /**
- * 滑动删除的主要响应方法。
- */
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- //如果删除按钮没有显示,并且手势滑动符合我们的条件
- //此处可以根据需要进行手势滑动的判断,如限制左滑还是右滑,我这里是左滑右滑都可以
- if (!isDeleteShow && Math.abs(velocityX) > Math.abs(velocityY)) {
- //在当前布局上,动态添加我们的删除按钮,设置按钮的各种参数、事件,按钮的点击事件响应我们的删除项监听器
- btnDelete = LayoutInflater.from(getContext()).inflate(R.layout.layout_button, null);
- btnDelete.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- //btnHide(btnDelete);
- viewGroup.removeView(btnDelete);
- btnDelete = null;
- isDeleteShow = false;
- onItemDeleteListener.onItemDelete(selectedItem);
- }
- });
- viewGroup = (ViewGroup)getChildAt(selectedItem - getFirstVisiblePosition());
- RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
- layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
- layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
- btnDelete.setLayoutParams(layoutParams);
- viewGroup.addView(btnDelete);
- btnShow(btnDelete);
- isDeleteShow = true;
- }else{
- setOnTouchListener(this);
- }
- return false;
- }
- /**
- * @类名称: OnItemDeleteListener
- * @描述: 删除按钮监听器
- * @throws
- * @author 徐纪伟
- * 2014年11月9日上午11:25:37
- */
- public interface OnItemDeleteListener{
- public void onItemDelete(int selectedItem);
- }
- /**
- * @方法名称: btnShow
- * @描述: 按钮显示时的动画
- * @param @param v
- * @return void
- * @throws
- * @author 徐纪伟
- * 2014年11月9日 上午11:25:12
- */
- private void btnShow(View v){
- v.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.btn_show));
- }
- /**
- * @方法名称: btnHide
- * @描述: 按钮隐藏时的动画
- * @param @param v
- * @return void
- * @throws
- * @author 徐纪伟
- * 2014年11月9日 上午11:25:23
- */
- private void btnHide(View v){
- v.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.btn_hide));
- }
- }
4、使用方法,布局文件,activity,很简单activity_main.xml:
- <?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/main_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <com.example.viewtest.MyListView
- android:id="@+id/my_listview"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- </com.example.viewtest.MyListView>
- </RelativeLayout>
listview的每一个item的布局文件,一个textview,item.xml:
- <?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="match_parent" >
- <TextView
- android:id="@+id/textView1"
- android:layout_width="wrap_content"
- android:layout_height="50dp"
- android:text="TextView" />
- </RelativeLayout>
activity,初始化listview,adapter的使用就不在介绍,跟普通的一样,唯一不同的就是,要给我们的自定义listview添加我们自定义的删除按钮单击事件,以此来响应我们的删除事件,MainActivity.java:
- package com.example.viewtest;
- import java.util.LinkedList;
- import java.util.List;
- import android.content.Context;
- import android.os.Bundle;
- import android.support.v7.app.ActionBarActivity;
- import android.view.LayoutInflater;
- import android.view.Menu;
- import android.view.MenuItem;
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.BaseAdapter;
- import android.widget.TextView;
- import com.example.viewtest.MyListView.OnItemDeleteListener;
- public class MainActivity extends ActionBarActivity {
- /**
- * 自定义listview对象
- */
- private MyListView myListview;
- /**
- * listView的数据集合
- */
- private List<String> contentList = new LinkedList<String>();
- /**
- * 自定义数据适配器
- */
- private MyAdapter adapter;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //初始化数据
- setData();
- myListview = (MyListView)findViewById(R.id.my_listview);
- adapter = new MyAdapter(this);
- myListview.setAdapter(adapter);
- //添加自定义listview的按钮单击事件,处理删除结果,和普通listview使用的唯一不同之处,
- myListview.setOnItemDeleteListener(new OnItemDeleteListener() {
- @Override
- public void onItemDelete(int index) {
- contentList.remove(index);
- adapter.notifyDataSetChanged();
- }
- });
- }
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- int id = item.getItemId();
- if (id == R.id.action_settings) {
- return true;
- }
- return super.onOptionsItemSelected(item);
- }
- /**
- * @类名称: MyAdapter
- * @描述: 自定义数据适配器
- * @throws
- * @author 徐纪伟
- * 2014年11月9日下午12:20:19
- */
- class MyAdapter extends BaseAdapter{
- private Context context;
- public MyAdapter(Context context) {
- this.context = context;
- }
- @Override
- public int getCount() {
- // TODO Auto-generated method stub
- return contentList.size();
- }
- @Override
- public Object getItem(int position) {
- // TODO Auto-generated method stub
- return contentList.get(position);
- }
- @Override
- public long getItemId(int position) {
- // TODO Auto-generated method stub
- return position;
- }
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- if (convertView == null) {
- convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
- }
- TextView textView = (TextView)convertView.findViewById(R.id.textView1);
- textView.setText(contentList.get(position));
- return convertView;
- }
- }
- /**
- * @方法名称: setData
- * @描述: 初始化数据
- * @param
- * @return void
- * @throws
- * @author 徐纪伟
- * 2014年11月9日 下午12:20:32
- */
- private void setData() {
- for (int i = 0; i < 30; i++) {
- contentList.add("Item "+i);
- }
- }
- }
运行效果:

再给button加上selector背景,更好看一些:selector_btn_red.xml
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:android="http://schemas.android.com/apk/res/android" >
- <item android:state_pressed="true" android:drawable="@drawable/btn_style_zero_pressed"></item>
- <item android:state_pressed="false" android:drawable="@drawable/btn_style_zero_normal"></item>
- </selector>
资源图片在附件源码中上传。
最终效果:

图片显示的位置在自定义listview中可以调整。

浙公网安备 33010602011771号