仿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效果如图: 图中我们可以看到,动画处的头像和文字是一起的,即同时并且是整体,注意,是整体进行缩放的 ...
随机推荐
- 如何将 Area 中的 Controller 放到独立的程序集?
目录 背景如何将 Area 中的 Controller 放到独立的程序集?备注 背景返回目录 本文假设您已经熟悉了 ASP.NET MVC 的常规开发方式.执行模型和关键扩展点,这里主要说一下如何使用 ...
- ecexl操作
/// <summary> /// 写入ecexl /// </summary> /// <param name="dt"></param ...
- GitHub创建SSH Keys
第一步:在用户主目录下,看有没有.ssh目录,如果有,再看看这个目录下 有没有id_rsa和id_rsa.pub这两个文件,如果已经有了,可直接跳到下一步,如果没有 打开Git Bash,创建SSH ...
- MySQL能够承受上亿万条的数据量的架构
MySQL能够承受上亿万条的数据量的架构 最近做的搜索引擎的数据量是越来越大估计了下在中国可能涉及到的1Kw的数据量,就全球来说也就是1K亿而已,最初是用的数据库是MySQL现在来说要做些优化,最终使 ...
- HDFS中PathFilter类
HDFS中PathFilter类 在单个操作中处理一批文件,这是很常见的需求.比如说处理日志的MapReduce作业可能需要分析一个月内包含在大量目录中的日志文件.在一个表达式中使用通配符在匹配多个文 ...
- WCF 学习笔记之异常处理
WCF 学习笔记之异常处理 1:WCF异常在配置文件 <configuration> <system.serviceModel> <behaviors> <s ...
- c# 数据库更新操作-文本更新和数值更新小差别
1.文本更新 string strName; sql = "update 模式表 a SET 模式名称 ='"+ strName +"'where a.模式ID =&qu ...
- Spring.Net-创建对象
1:通过构造函数创建对象 在配置文件中,指明对象类型<object id="" type="类型全名,程序集名" /> 在代码中指定对象 ...
- python 变量命名规则
变量命名: 1.语法: (下划线或字母)+(任意数目的字母.数字或下划线) 变量名必须以下划线或字母开头,而后面接任意数目的字母.数字或下划线. 区分大小写: SPAM和spam不同 禁止使用保留 ...
- 基于gulp编写的一个简单实用的前端开发环境好了,安装完Gulp后,接下来是你大展身手的时候了,在你自己的电脑上面随便哪个地方建一个目录,打开命令行,然后进入创建好的目录里面,开始撸代码,关于生成的json文件请点击这里https://docs.npmjs.com/files/package.json,打开的速度看你的网速了注意:以下是为了演示 ,我建的一个目录结构,你自己可以根据项目需求自己建目
自从Node.js出现以来,基于其的前端开发的工具框架也越来越多了,从Grunt到Gulp再到现在很火的WebPack,所有的这些新的东西的出现都极大的解放了我们在前端领域的开发,作为一个在前端领域里 ...