? ? ? ? 今天研究了一下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中可以调整。
? ?
原文:http://men4661273.iteye.com/blog/2153857