首先我们在日常的软件使用中已经有很多这样的例子了,例如我们用到的QQ、微信都具有这样的功能。而本文只是简单的起一个引导的作用,在已经存在的listview的基础上对其进行改造,使它能更好的满足
我们在开发当中遇到的需求。
首先,我们先看下我们要达到的效果:
看到效果图,首先我们来思考一下,要实现这样的效果,我们需要进行怎样的步骤?
思路:可以确定的是,我们肯定通过手势的从右自左的滑动,这样,我们就想肯定要获取到滑动之前的X,Y坐标和滑动结束的X,Y坐标。
通过判断开始和结束时坐标距离的绝对值来计算出滑动的距离。在这之前,我们应该设置一个值,来表示当大于这个值时。
我们就应该响应滑动事件,及显示删除按钮。如何显示一个删除按钮呢?我们这儿采用Android自带的一个控件:PopupWindow。
通过上面简单的分析之后,我们就来看具体的代码实现。然后在慢慢了解编码过程中,我们需要注意的细节问题。
首先,来看下目录结构:
准备两个布局文件:1、activity_main.xml 主界面布局文件。2、btn_delete.xml Button删除按钮的布局文件
下面是布局文件的具体代码实现:
activity_main.xml:
[html]
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayout
xmlns:android="/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hql.listviewitemdelete.widget.ListViewDeleteItem
android:id="@+id/list_item_delete"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.hql.listviewitemdelete.widget.ListViewDeleteItem>
</LinearLayout>
btn_delete.xml:
[html]
<?xmlversion="1.0"encoding="utf-8"?>
<Button
android:id="@+id/btn_delete"
xmlns:android="/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#ff0202"
android:text="删除"/>
布局文件都很简单,相信大家都能看得懂。
接下来,我们就来编写ListViewDeleteItem,这个类,因为我们是在listview进行扩展开发,所以我们应该是继承自listview。
[java]
/**
*listview滑动删除item
*CreatedbyMr.Hon/11/16.
*/
publicclassListViewDeleteItemextendsListView
接下来我们根据刚刚的思路,首先应该定义一下变量:开始X,Y坐标、结束X,Y坐标、相应滑动的距离、是否正在滑动、布局加载器、
PopupWindow、PopupWindow宽高、删除按钮Button、删除按钮的回调接口、手指现在触摸到的view、和手指触摸到的view的位置。
以上就是我们应该要定义的成员变量。
[java]
//手指按下的X,Y坐标
privateintstartX;
privateintstartY;
//手指移动结束时的X,Y坐标
privateintendX;
privateintendY;
//用户手势滑动的距离
privateintmoveLength;
//是否正在滑动
privatebooleanisSliding;
//布局加载器
privateLayoutInflatermInflater;
//pop弹出
privatePopupWindowmPopupWindow;
//pop高度
privateintmPopupWindowHeight;
//pop宽度
privateintmPopupWindowWidth;
//删除按钮
privateButtonmBtnDelete;
//删除按钮的回调接口
publicBtnDeleteClickListenermListener;
//当前手指触摸的View
privateViewmCurrentView;
//当前手指触摸的位置
privateintmCurrentViewPos;
现在我们需要重写含有两个参数的构造方法,并对部分变量就行初始化。
[java]
publicListViewDeleteItem(Contextcontext,AttributeSetattrs)
{
super(context,attrs);
//实例化布局加载器
mInflater=LayoutInflater.from(context);
//getScaledTouchSlop是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件,如果小于这个距离就不触发移动控件。
moveLength=ViewConfiguration.get(context).getScaledTouchSlop();
//获取到删除按钮的布局文件
Viewview=mInflater.inflate(R.layout.btn_delete,null);
//查找删除按钮
mBtnDelete=(Button)view.findViewById(R.id.btn_delete);
//实例化POP,并且绑定视图,和设置宽高
mPopupWindow=newPopupWindow(view,LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.WRAP_CONTENT);
//先调用下measure,否则拿不到宽和高
mPopupWindow.getContentView().measure(0,0);
//获取button的宽高
mPopupWindowHeight=mPopupWindow.getContentView().getMeasuredHeight();
mPopupWindowWidth=mPopupWindow.getContentView().getMeasuredWidth();
}
上面的主要是对布局加载器进行初始化,加载一个布局文件,然后绑定到PopupWindow中,并且测出button在PopupWindow中的宽高。
做完以上操作,我们现在就需要实现我们最重要的部分了,即手势的判断。
接下来我们重写dispatchTouchEvent(MotionEvent ev)这个方法。这个方法主要是对点击事件的分发。
首先,我们通过ev这个参数来获取到用户的点击事件类型,并且用两个局部变量,记录下点击时的X,Y坐标。
[java]
//获取点击类型
intactiion=ev.getAction();
//获取按下时的x,y坐标
intx=(int)ev.getX();
inty=(int)ev.getY();
对此,我们应该判断用户的两个动作:按下和移动
首先我们先来看按下事件的处理:
[java]
switch(actiion)
{
//按下
caseMotionEvent.ACTION_DOWN:
startX=x;
startY=y;
//如果当前的pop显示,则将其隐藏掉
if(mPopupWindow.isShowing())
{
dismissPopWindow();
returnfalse;
}
//获得当前手指按下时的item的位置
mCurrentViewPos=pointToPosition(startX,startY);
//获得当前手指按下时的item
Viewview=getChildAt(mCurrentViewPos-getFirstVisiblePosition());
mCurrentView=view;
break;
将开始获取到的X,Y坐标赋值给定义的变量。并且判断PopupWindow是否正在显示,如果是则关闭,并且返回false。
之后通过pointToPosition()方法获取到当前按下的item的位置。通过getChildAt()获取到当前点击item位置所对应的view。
以上就是用户按下的事件。
下面来处理用户移动时的事件。
[java]
//移动
caseMotionEvent.ACTION_MOVE:
endX=x;
endY=y;
intdx=endX-startX;
intdy=endY-startY;
/**
*判断是否是从右到左的滑动
*/
if(endX<startX&&Math.abs(dx)>moveLength&&Math.abs(dy)<moveLength)
{
isSliding=true;
}
break;
上面是对事件的分发处理,下面我们就来看看事件的处理即:onTouchEvent(MotionEvent ev)方法。
[java]
intaction=ev.getAction();
if(isSliding)
{
switch(action)
{
caseMotionEvent.ACTION_UP:
isSliding=false;
break;
caseMotionEvent.ACTION_MOVE:
int[]location=newint[2];
mCurrentView.getLocationOnScreen(location);
//设置pop显示的位置
mPopupWindow.showAtLocation
(mCurrentView,Gravity.LEFT|Gravity.TOP,
location[0]+mCurrentView.getWidth(),
location[1]+mCurrentView.getHeight()/2-mPopupWindowHeight/2);
mBtnDelete.setOnClickListener(newOnClickListener()
{
@Override
publicvoidonClick(Viewview)
{
if(mListener!=null)
{
mListener.btnClick(mCurrentViewPos);
mPopupWindow.dismiss();
}
}
});
break;
}
}
returnsuper.onTouchEvent(ev);
首先,我还是要先获取到用户的点击事件类型,并且判断是否正在移动,当用户手势抬起的时候,将是否正在滑动设置为false。
处理用户移动的事件,设置PopupWindow的显示位置,并且给button设置点击事件。
[java]
publicvoidsetBtnDeleteClickListener(BtnDeleteClickListenerlistener)
{
mListener=listener;
}
publicinterfaceBtnDeleteClickListener
{
voidbtnClick(intposition);
}
/**
*隐藏pop
*/
privatevoiddismissPopWindow()
{
if(mPopupWindow!=null&&mPopupWindow.isShowing())
{
mPopupWindow.dismiss();
}
}
上面就是定义一个接口并写隐藏pop的方法。以上全部就是自定义的全部代码。接下来只需要将其写到布局文件当中。
demo下载地址:/detail/poison_h/9275487