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的自定义view实现一个公章的效果,据说这是华为之前的面试题,我想了下,要是公章的效果,最外层是一个圆,里面是一个五角星,但是这文字怎么画呢, ...
- Android 自定义View跑马灯效果(一)
今天通过书籍重新复习了一遍自定义VIew,为了加强自己的学习,我把它写在博客里面,有兴趣的可以看一下,相互学习共同进步: 通过自定义一个跑马灯效果,来诠释一下简单的效果: 一.创建一个类继承View, ...
- Android自定义View 画弧形,文字,并增加动画效果
一个简单的Android自定义View的demo,画弧形,文字,开启一个多线程更新ui界面,在子线程更新ui是不允许的,但是View提供了方法,让我们来了解下吧. 1.封装一个抽象的View类 B ...
- Android自定义View(LimitScrollerView-仿天猫广告栏上下滚动效果)
转载请标明出处: http://blog.csdn.net/xmxkf/article/details/53303872 本文出自:[openXu的博客] 1分析 2定义组合控件布局 3继承最外层控件 ...
- Android 自定义View合集
自定义控件学习 https://github.com/GcsSloop/AndroidNote/tree/master/CustomView 小良自定义控件合集 https://github.com/ ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
- Android 自定义view(二) —— attr 使用
前言: attr 在前一篇文章<Android 自定义view -- attr理解>已经简单的进行了介绍和创建,那么这篇文章就来一步步说说attr的简单使用吧 自定义view简单实现步骤 ...
- Android 自定义View及其在布局文件中的使用示例(二)
转载请注明出处 http://www.cnblogs.com/crashmaker/p/3530213.html From crash_coder linguowu linguowu0622@gami ...
- Android自定义View
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24252901 很多的Android入门程序猿来说对于Android自定义View ...
随机推荐
- Python系列之 - multiprocessing
由于GIL的存在,python中的多线程其实并不是真正的多线程,如果想要充分地使用多核CPU的资源,在python中大部分情况需要使用多进程. multiprocessing包是Python中的多进程 ...
- springboot启动报错
新建springboot整合aop记录web日志的过程中启动失败 错误如下: ***************************APPLICATION FAILED TO START******* ...
- 0417 jsBom操作+Dom再次整理
BOM 1.Windows对象 window.open("打开的地址","打开的位置")window.opener:打开此页面的上一个页面对象window.cl ...
- 浅谈轮播图(原生JavaScript实现)
现在各种轮播图插件,玲琅满目,用起来也非常方便,通常只需要选择元素然后传入参数就可以了.但是,和授人以鱼不如授人以渔一样的道理,不管怎样最基本的轮播图原理还是应当掌握的.这样不仅有利于我们自己写出来满 ...
- PHPCMS v9.6.0 任意用户密码重置
参考来源:http://wooyun.jozxing.cc/static/bugs/wooyun-2016-0173130.html 他分析的好像不对.我用我的在分析一次. 先来看poc: /inde ...
- [ZJOI2006]物流运输 SPFA+DP
题目描述 物流公司要把一批货物从码头A运到码头B.由于货物量比较大,需要n天才能运完.货物运输过程中一般要转停好几个码头.物流公司通常会设计一条固定的运输路线,以便对整个运输过程实施严格的管理和跟踪. ...
- FJOI2017 RP++
嗯如果算得没错大概十二小时之后就是省选二试了 这次考试貌似就在我们学校 虽然机子挺旧的基本没用过 平时训练都是在专门的机房 其实貌似压力不是很大 因为一试跪了TAT 那时候还是图样 T3按照惯例是 ...
- python变量、条件循环语句
1. 变量名 - 字母 - 数字 - 下划线 #数字不能开头:不能是关键字:最好不好和python内置的函数等重复 2. 条件语句 缩进用4个空格(Tab键)注意缩进如果是空格键和Tab键混用, ...
- VMware下安装Linux(CentOs6.3)操作系统
VMware 10.0.2 CentOs 6.3 VMware的安装以及CentOs的下载比较简单,这里不再描述 1.创建新的虚拟机 2.选择典型 3.选择稍后安装操作系统 4.选择如图所示 5.虚拟 ...
- C语言程序设计第六次作业——循环结构(2)
C语言程序设计第六次作业--循环结构(2) 之前的博客园图片没处理好,对大家说一声抱歉.希望大家能够多多指出我的错误,我来认真修改 ^ - ^ !. (1)改错题 序列求和:输入一个正实数eps,计算 ...