自定义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: [email protected]
 * 创建时间: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中可以调整。

   

猜你喜欢

转载自men4661273.iteye.com/blog/2153857
今日推荐