仿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效果如图: 图中我们可以看到,动画处的头像和文字是一起的,即同时并且是整体,注意,是整体进行缩放的 ...
随机推荐
- Getting Started with Core Data
Getting Started with Core Data Getting Started with Core Data Coreframework支持创建对象模型封装你的应用数据和逻辑满足MVC设 ...
- django安装配置及测试
django安装之前我们假设你已经安装了python,和mysql(不是必须的):(如果没有google一下挺简单不介绍了)下面直接介绍django的安装配置:到下面连接可以下载www.djangop ...
- CSDN CODE平台,中国版Github简要使用说明
CSDN CODE平台,中国版Github简要使用说明!(多图慎入) 楼主说 以前一直看到别人在用github发布自己的代码,各种牛逼,各种羡慕嫉妒恨.最后终于受不了了,也去注册了一个,注册到没什 ...
- MongoDB学习(翻译5)
C#驱动序列化文档对象 介绍 本文档基于C#官方驱动1.8版本. 本节C#驱动教程谈论C#类到BSON对象的序列化和反序列化.序列化是映射一个对象到可保存到MongoDB库中BSON对象的过程,反序列 ...
- MySql主从配置实践及其优势浅谈
MySql主从配置实践及其优势浅谈 1.增加两个MySQL,我将C:\xampp\mysql下的MYSQL复制了一份,放到D:\Mysql2\Mysql5.1 修改my.ini(linux下应该是my ...
- EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载
EF如何操作内存中的数据和加载外键数据:延迟加载.贪婪加载.显示加载 之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需 ...
- 拦截所有AJAX调用,重点处理服务器异常
拦截所有AJAX调用,重点处理服务器异常 背景 上篇文章http://www.cnblogs.com/happyframework/p/3241063.html介绍了如何以AOP的形式处理服务器异常, ...
- sql server DateTime相关内置函数总结
本文部分内容参考msdn帮助文档和博客园!汇总备忘 1.获取当前日期 getdate()函数以datetime数据类型的格式返回当前SQLServer服务器所在计算机的日期和时间.其语法格式 ...
- kinect (oldest one) (libfreenect with py_kinect) on linux ubuntu14.04 x64
freenect libs Where is the resource? Here :P : https://github.com/OpenKinect/libfreenect To make sur ...
- 【Machine Learning】单参数线性回归 Linear Regression with one variable
最近开始看斯坦福的公开课<Machine Learning>,对其中单参数的Linear Regression(未涉及Gradient Descent)做个总结吧. [设想] ...