仿qq的条目抽屉动画效果_ViewDragHelper
GitHub地址:
https://github.com/OOOOOldZhu/DrawerItemView
import android.content.Context; import android.support.v4.view.ViewCompat; import android.support.v4.widget.ViewDragHelper; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.FrameLayout; public class SwipeLayout extends FrameLayout { private View content; private View delete; ViewDragHelper dragHelper; public SwipeLayout(Context context) { this(context, null); } public SwipeLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public SwipeLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); //初始化ViewDragHelper dragHelper = ViewDragHelper.create(this, callback); } //只有完成系统对xml文件完成最后标签的解析,才能获得子控件 @Override protected void onFinishInflate() { super.onFinishInflate(); content = getChildAt(0); delete = getChildAt(1); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { content.layout(0, 0, content.getMeasuredWidth(), content.getMeasuredHeight()); int L = content.getRight(); //content(右下角)的right(距原点的x距离)即为 delete控件的左上角的x坐标 delete.layout(L, 0, L + delete.getMeasuredWidth(), delete.getMeasuredHeight()); } @Override public boolean onInterceptTouchEvent(MotionEvent ev) {
//让helper处理拦截事件 boolean result = dragHelper.shouldInterceptTouchEvent(ev); return result; } float downX,downY; @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); downY = event.getY(); break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); //计算移动的距离 float dx = moveX - downX; float dy = moveY - downY; //判断到底偏向于哪个方向 if(Math.abs(dx)>Math.abs(dy)){ //说明是偏向水平方向,那么就认为用户想滑动条目,此时应该让listview不要拦截 requestDisallowInterceptTouchEvent(true); } break; case MotionEvent.ACTION_UP: break; } dragHelper.processTouchEvent(event); return true; } // 回调方法 ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return true; } @Override public int getViewHorizontalDragRange(View child) { return 1; } //修正子控件的位置坐标的方法 @Override public int clampViewPositionHorizontal(View child, int left, int dx) { //限制content if(child==content){ if(left>0){ left = 0; }else if(left<-delete.getMeasuredWidth()){ left = -delete.getMeasuredWidth(); } }else if(child==delete){ //限制delete if(left>content.getMeasuredWidth()){ left = content.getMeasuredWidth(); }else if(left<(content.getMeasuredWidth()- delete.getMeasuredWidth())) { left = (content.getMeasuredWidth()- delete.getMeasuredWidth()); } } return left; } @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); //如果移动的是content,那么让delete伴随移动 if(changedView==content){ // int newLeft = delete.getLeft()+dx; // delete.layout(newLeft,0,newLeft+delete.getMeasuredWidth(),delete.getMeasuredHeight()); ViewCompat.offsetLeftAndRight(delete,dx); }else if(changedView==delete){ //让content进行伴随移动 ViewCompat.offsetLeftAndRight(content,dx); } //回调接口的方法 if(listener!=null){ if(content.getLeft()==0){ listener.onClose(SwipeLayout.this); }else if(content.getLeft()==-delete.getMeasuredWidth()){ listener.onOpen(SwipeLayout.this); } } } @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); if(content.getLeft()>-delete.getMeasuredWidth()/2){ //关闭抽屉 closeLayout(); }else { //打开抽屉 openLayout(); } } }; /** * 打开 */ public void openLayout() { dragHelper.smoothSlideViewTo(content,-delete. getMeasuredWidth(),0); ViewCompat.postInvalidateOnAnimation(this); } /** * 关闭 */ public void closeLayout() { dragHelper.smoothSlideViewTo(content,0,0); ViewCompat.postInvalidateOnAnimation(this); } @Override public void computeScroll() { super.computeScroll(); if(dragHelper.continueSettling(true)){ ViewCompat.postInvalidateOnAnimation(this); } } private OnSwipeListener listener; public void setOnSwipeListener(OnSwipeListener listener){ this.listener = listener; } public interface OnSwipeListener{ void onOpen(SwipeLayout currentLayout); void onClose(SwipeLayout currentLayout); } }
MainActivity中:
import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.BaseAdapter; import android.widget.ListView; import android.widget.TextView; import butterknife.Bind; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity { private ListView listview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listview = (ListView) findViewById(R.id.listview); listview.setAdapter(new MyAdapter()); //监听listview的滚动 listview.setOnScrollListener(new AbsListView.OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if(openedLayout!=null){ openedLayout.closeLayout(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); } SwipeLayout openedLayout;//用来记录打开的SwipeLayout class MyAdapter extends BaseAdapter implements SwipeLayout.OnSwipeListener{ @Override public int getCount() { return Constant.NAMES.length; } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { MyHolder myHolder = null; if(convertView==null){ convertView = View.inflate(parent.getContext(), R.layout.adapter_list, null); myHolder = new MyHolder(convertView); convertView.setTag(myHolder); }else { myHolder = (MyHolder) convertView.getTag(); } //绑定数据 myHolder.tvName.setText(Constant.NAMES[position]); //设置监听器 myHolder.swipeLayout.setOnSwipeListener(this); return convertView; } @Override public void onOpen(SwipeLayout currentLayout) { //应该关闭当前已经打开的 if(openedLayout!=null && openedLayout!=currentLayout){ openedLayout.closeLayout(); } openedLayout = currentLayout; } @Override public void onClose(SwipeLayout currentLayout) { if(openedLayout==currentLayout){ openedLayout = null; } } } static class MyHolder { @Bind(R.id.tv_name) TextView tvName; @Bind(R.id.tv_delete) TextView tvDelete; @Bind(R.id.swipeLayout) SwipeLayout swipeLayout; MyHolder(View view) { ButterKnife.bind(this, view); } } }
仿qq的条目抽屉动画效果_ViewDragHelper的更多相关文章
- 【Android UI设计与开发】第03期:引导界面(三)仿微信引导界面以及动画效果
基于前两篇比较简单的实例做铺垫之后,这一篇我们来实现一个稍微复杂一点的引导界面的效果,当然也只是稍微复杂了一点,对于会的人来说当然还是so easy!正所谓会者不难,难者不会,大概说的就是这个意思了吧 ...
- android开发学习 ------- 仿QQ侧滑效果的实现
需要做一个仿QQ侧滑删除的一个效果: 一开始是毫无头绪,百度找思路,找到 https://blog.csdn.net/xiaxiazaizai01/article/details/53036994 ...
- Android高仿qq及微信底部菜单的几种实现方式
最近项目没那么忙,想着开发app的话,有很多都是重复,既然是重复的,那就没有必要每次都去写,所以就想着写一个app通用的基本框架,这里说的框架不是什么MVC,MVP,MVVM这种,而是app开发的通用 ...
- wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果
上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个 两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingicho ...
- Fragment,仿QQ空间
转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451 在今天的这篇文章当中,我依然会以实战加理论结合 ...
- Android仿QQ窗口的抖动的动画效果
就是仿照QQ窗口的抖动效果,在项目的res下创建anim文件夹,再创建两个xml文件:cycle.xml . myanim.xml cycle.xml : <?xml version ...
- Android -- 自定义ViewGroup+贝塞尔+属性动画实现仿QQ点赞效果
1,昨天我们写了篇简单的贝塞尔曲线的应用,今天和大家一起写一个QQ名片上常用的给别人点赞的效果,实现效果图如下: 红心的图片比较丑,见谅见谅(哈哈哈哈哈哈).... 2,实现的思路和原理 从上面的效果 ...
- android 自定义scrollview 仿QQ空间效果 下拉伸缩顶部图片,上拉回弹 上拉滚动顶部title 颜色渐变
首先要知道 自定义scrollview 仿QQ效果 下拉伸缩放大顶部图片 的原理是监听ontouch事件,在MotionEvent.ACTION_MOVE事件时候,使用不同倍数的系数,重置布局位置[ ...
- 安卓仿QQ红包领取详情界面动画
为了能清楚的看到这个效果,本人不惜几次花费重金给众群叼发放红包,来查看红包领取详情界面的动画效果,QQ效果如图: 图中我们可以看到,动画处的头像和文字是一起的,即同时并且是整体,注意,是整体进行缩放的 ...
随机推荐
- SSH整合之_架构的历史序列图
只用jsp最原始的架构 jsp+DB的2层架构 jsp+DB+_Entity的2层架构 jsp+DB+_Entity3_+Service的三层架构 jsp+DB+_Entity3_+Service_H ...
- storm源码之巧用java反射反序列化clojure的defrecord获取属性值
[原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 [原创]storm源码之巧用java反射反序列化clojure的defrecord获取属性值 storm源 ...
- 百度地图定位SDK 之构想
百度地图定位 前提 从香港旅游回来,心中油然升起一股热血滂湃,激励自己发现市场需求,向创业奋进,朝着梦想前进. 简介 百度Android定位SDK支持Android1.5以及以上设备,提供: 定位功能 ...
- IL反编译的实用工具
初识Ildasm.exe——IL反编译的实用工具 Ildasm.exe 概要: 一.前言: 微软的IL反编译实用程序——Ildasm.exe,可以对可执行文件(ex,经典的控制台Hello Wor ...
- javac命令
javac命令 javac命令初窥 注:以下红色标记的参数在下文中有所讲解. 用法: javac <options> <source files> 其中, 可能的选项包括: ...
- Http的四种post方式
1.引言 HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS.GET.HEAD.POST.PUT.DELETE.TRACE.CONNECT 这几种.其中 POST 一般用来向服务端提交 ...
- sharepoint 2013 文档库eventhandle权限控制
记录一下如何在sharepoint server 2013文档库中,使用eventhandle控制文档库document library的条目item权限. ///<summary> // ...
- 【Unity 3D】教程(1)建立场景
1.新建一个地形 在菜单中选择Terrain,新建一个地形 接下来在右边的“编辑高度”中,用笔刷绘出地形高度,如图: 2.地形纹理 接下来我们给地形贴上纹理,纹理资源我们使用unity自带的, 在Pr ...
- JSP引擎的工作原理
JSP运行环境: 执行JSP代码需要在服务器上安装JSP引擎,比较常见的引擎有WebLogic和Tomcat.把这些支持JSP的web服务器配置好后.就可以再客户端通过浏览器来访问JSP页面了.默认端 ...
- HDU 2064 菜鸡第一次写博客
果然集训就是学长学姐天天传授水铜的动态规划和搜索,今天讲DP由于困意加上面瘫学长"听不懂就是你不行"的呵呵传授,全程梦游.最后面对连入门都算不上的几道动态规划,我的内心一片宁静,甚 ...