Android中自定义view实现侧滑效果
效果图:
看网上的都是两个view拼接,默认右侧的不显示,水平移动的时候把右侧的view显示出来。但是看最新版qq上的效果不是这样的,但给人的感觉却很好,所以献丑来一发比较高仿的。
知识点:
1、viewdraghelper 的用法;
2、滑动冲突的解决;
3、自定义viewgroup。
viewdraghelper 出来已经比较久了 相信大家都比较熟悉,不熟悉的话google一大把这里主要简单用一下它的几个方法
1、trycaptureview(view child, int pointerid) :确定那个子view可以滑动
2、 getviewhorizontaldragrange(view child):用我蹩脚的英语翻译一下是‘返回的是子view在水平方向上可移动的大小,以像素为单位,返回0的时候表示水平方向上不能拖动'
3、clampviewpositionhorizontal(view child, int left, int dx):在这里可以对边界进行检查,left和dx分别代表即将移动到的位置
4、onviewpositionchanged(view changedview, int left, int top,
int dx, int dy):当要捕获view,由于拖曳或者设定而发生位置变更时回调
它的基本用法是:
public swipelayout(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(); } private void init() { viewdraghelper = viewdraghelper.create(this, callback); } public boolean onintercepttouchevent(motionevent ev) { boolean result = viewdraghelper.shouldintercepttouchevent(ev); } public boolean ontouchevent(motionevent event) { viewdraghelper.processtouchevent(event); return true; }
1)、在构造方法中创建
2)、在onintercepttouchevent 中判断是否拦截
3 )、 在 ontouchevent出来事件
好了 最不好理解的已经搞定了。接下来看看具体实现:
首先看布局:
<linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" > <scrollviewgroup.lly.com.swiplayout.swipelayout android:id="@+id/swipelayout" android:layout_width="match_parent" android:layout_height="wrap_content" > <!-- delete区域的布局 --> <include layout="@layout/layout_delete" /> <!-- item内容的布局 --> <include layout="@layout/layout_content" /> </scrollviewgroup.lly.com.swiplayout.swipelayout> </linearlayout>
这个没什么好说的,一个自定义viewgroup包含两个子控件。
接着看看swipelayout是怎么实现的:
@override protected void onfinishinflate() { super.onfinishinflate(); deleteview = getchildat(0); contentview = getchildat(1); } @override protected void onsizechanged(int w, int h, int oldw, int oldh) { super.onsizechanged(w, h, oldw, oldh); deleteheight = deleteview.getmeasuredheight(); deletewidth = deleteview.getmeasuredwidth(); contentwidth = contentview.getmeasuredwidth(); screenwidth = getwidth(); } @override protected void onlayout(boolean changed, int left, int top, int right, int bottom) { // super.onlayout(changed, left, top, right, bottom); deleteview.layout(screenwidth - deletewidth, 0, (screenwidth - deletewidth) + deletewidth, deleteheight); contentview.layout(0, 0, contentwidth, deleteheight); }
上面代码进行了一些初始化的操作,重点看看onlayout里面的,我们继承的是framelayout 这里先画出来 deleteview并让他在右边,然后在上面改了一层contentview,这样显示的时候只会显示contentview。
接下来看ontouch方法
public boolean ontouchevent(motionevent event) { //如果当前有打开的,则下面的逻辑不能执行 if(!swipelayoutmanager.getinstance().isshouldswipe(this)){ requestdisallowintercepttouchevent(true); return true; } switch (event.getaction()) { case motionevent.action_down: downx = event.getx(); downy = event.gety(); break; case motionevent.action_move: //1.获取x和y方向移动的距离 float movex = event.getx(); float movey = event.gety(); float delatx = movex - downx;//x方向移动的距离 float delaty = movey - downy;//y方向移动的距离 if(math.abs(delatx)>math.abs(delaty)){ //表示移动是偏向于水平方向,那么应该swipelayout应该处理,请求父view不要拦截 requestdisallowintercepttouchevent(true); } //更新downx,downy downx = movex; downy = movey; break; case motionevent.action_up: break; } viewdraghelper.processtouchevent(event); return true; }
上面主要就是对事件冲突的处理,当是水平移动的时候就请求父视图不要拦截。
接下来来重点就来了
private viewdraghelper.callback callback = new viewdraghelper.callback() { @override public boolean trycaptureview(view child, int pointerid) { return child==contentview; } @override public int getviewhorizontaldragrange(view child) { return deletewidth; } @override public int clampviewpositionhorizontal(view child, int left, int dx) { if(child==contentview){ if(left>0)left = 0; if(left<-deletewidth)left = -deletewidth; } return left; } @override public void onviewpositionchanged(view changedview, int left, int top, int dx, int dy) { super.onviewpositionchanged(changedview, left, top, dx, dy); //判断开和关闭的逻辑 if(contentview.getleft()==0 && currentstate!=swipestate.close){ //说明应该将state更改为关闭 currentstate = swipestate.close; //回调接口关闭的方法 if(listener!=null){ listener.onclose(gettag()); } //说明当前的swipelayout已经关闭,需要让manager清空一下 swipelayoutmanager.getinstance().clearcurrentlayout(); }else if (contentview.getleft()==-deletewidth && currentstate!=swipestate.open) { //说明应该将state更改为开 currentstate = swipestate.open; //回调接口打开的方法 if(listener!=null){ listener.onopen(gettag()); } //当前的swipelayout已经打开,需要让manager记录一下下 swipelayoutmanager.getinstance().setswipelayout(swipelayout.this); } } @override public void onviewreleased(view releasedchild, float xvel, float yvel) { super.onviewreleased(releasedchild, xvel, yvel); if(contentview.getleft()<-deletewidth/2){ //应该打开 open(); }else { //应该关闭 close(); } } };
上面这段代码里面的方法一开始我们都说过了,在来看下在trycaptureview中我们让 contentview可以滑动,在getviewhorizontaldragrange中却东滑动范围是deletewidth,在clampviewpositionhorizontal中对边界进行了下限制,在onviewpositionchanged中进行状态的更新, 最后在手指抬起的时候让view自动回滚,
/** * 打开的方法 */ public void open() { viewdraghelper.smoothslideviewto(contentview,-deletewidth,contentview.gettop()); viewcompat.postinvalidateonanimation(swipelayout.this); } /** * 关闭的方法 */ public void close() { viewdraghelper.smoothslideviewto(contentview,0,contentview.gettop()); viewcompat.postinvalidateonanimation(swipelayout.this); }; public void computescroll() { if(viewdraghelper.continuesettling(true)){ viewcompat.postinvalidateonanimation(this); } }
这里注意一定要重写computescroll方法,不然滑动效果动一下就不动了。
至此这个自定义framelayout就完成了
但是发现一个问题,我们在已经滑动出来的view中上下滑动时,这个view的deleteview还是显示状态,所以还要在activity中处理一下:
recyview.setonscrolllistener(new recyclerview.onscrolllistener() { @override public void onscrollstatechanged(recyclerview recyclerview, int newstate) { super.onscrollstatechanged(recyclerview, newstate); } @override public void onscrolled(recyclerview recyclerview, int dx, int dy) { super.onscrolled(recyclerview, dx, dy); if(dy>0 || dy<0){ swipelayoutmanager.getinstance().closecurrentlayout(); } } });
当这个recyclerview是上下滑动时,让子view复位。
收工。
ps:本来是在eclipse中listview中实现的,但是想想google都已经不支持eclipse了,而listview也快被recyclerview代替了,所以最后还是切换到android studio,用recyclerview实现了一套。
以上所述是小编给大家介绍的android中自定义view实现侧滑效果,希望对大家有所帮助
推荐阅读
-
Android中自定义view实现侧滑效果
-
Android侧滑效果简单实现代码
-
Android UI实现SlidingMenu侧滑菜单效果
-
Android自定义View控件实现刷新效果
-
Android 自定义view和属性动画实现充电进度条效果
-
Android UI实现SlidingMenu侧滑菜单效果
-
Android实现仿网易今日头条等自定义频道listview 或者grideview等item上移到另一个view中
-
Android自定义View实现闪耀字体效果
-
Android使用ViewDragHelper实现QQ6.X最新版本侧滑界面效果实例代码
-
Android中SwipeBack实现右滑返回效果