仿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);

        }
    }
}
时间: 2024-11-08 17:26:17

仿qq的条目抽屉动画效果_ViewDragHelper的相关文章

Android动画——仿vivo X6闪充动画效果

做程序猿这么久一直没有写博客,是不正常的,故以此为第一篇博客,开始我的博客生涯. 前不久,看到一篇博客,关于X6闪充动画的效果,是一个叫什么“瓶子盖子”写的,暂时就叫这个名字吧,具体名字没记清(sorry).跑了一下他的代码,发现各种卡顿...一查他的代码发现,在死循环里面不停地new Message(),不卡有鬼了...当然,我并没有对他有不敬的意思,只是想改良一下效果. 先上vivo X6闪充真机效果图: 充电时会不停地旋转,效果绚丽. 下面讲讲实现原理: 该动画实际上是由四条弧线,和中间的

仿电视关闭的一个动画效果

https://github.com/yy1300326388/TVOffAnimation https://github.com/yuantops/TopsTVPlayer https://github.com/tlasnier/TV-replay https://github.com/feer921/HomeTv https://github.com/MediaBrowser/MediaBrowser.AndroidTv https://github.com/RyanFu/tv_animat

duilib制作窗体动画效果

转载请说明原出处,谢谢~·http://blog.csdn.net/zhuhongshu/article/details/49026605 最近一段时间没写博客了,感觉最近没有遇到什么必须解决的bug.在一年前我把自己写的仿酷狗音乐播放器Demo写到博客时,我在博客末尾写过以后会做异形窗体和窗体动画的功能.异形窗体在半年前大概做完并且集成到我的库里了,但是窗体动画Demo没有写到博客.之前就有网友问我窗体动画的制作方法,一直懒着没写,不好意思···. 今天把窗体动画的制作思路和Demo说明一下.

Fragment,仿QQ空间

转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451          在今天的这篇文章当中,我依然会以实战加理论结合的方式教大家如何设计出自己觉得很炫的UI界面.好的,话不多说,进入正题.今天的这篇文章主要是以仿QQ空间的底部菜单栏效果为主,实现的效果有: <1>实现了点击按钮时的切换图片效果: <2>实现了点击按钮时的切换界面效果: <3>实现了点击中间圆形按钮时弹出菜单以及按钮图片切

iOS_28仿QQ空间登录与退出

最终效果图如下: 注意事项: 输入框的return Key Main.storyboard中为 LoginController 设置一个storyboardID, 以便可以在代码中通过Storyboard对象实例,创建Main.storyboard里面的控制器 仿QQ窗口抖动 dispach_after模拟延时 输入框的return Key的不同处理方式 Login控制器代码 // // LoginController.m // 28_QQ空间 // // Created by beyond o

CSS3实战开发:仿天猫首页图片展示动画特效实战开发

各位网友大家好,我是陌上花会开,人称陌陌.今天我带领大家开发一个仿天猫首页图片展示动画特效的案例.一如往常,我既不提供源码给大家,也不提供Demo给大家,只是希望大家能跟着我的讲解,然后将代码一步步复制到本地,本人可以保证,页面上的代码复制到本地,绝对百分百运行,且得到与陌陌一样的运行效果.我这么做只为激起大伙的动手能力,望大家能明白我的用心. 好了,不废话了,直接本篇的实战开发吧. 我们看一下我们今天要做的实战案例效果图: 1. 鼠标划过前: 2. 鼠标划过右侧的图片时: 可能大伙看这个静态截

wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果

上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果 这一篇带来一个  两条贝塞尔曲线的应用 : 仿qq未读消息去除效果. 转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50503630 老规矩,先上效果图: qq的未读消息去除很炫酷,其实就是用了两条贝塞尔曲线,我们按思路来,先来画两个圆,及两条贝塞尔曲线,辅助点为圆心y坐标的一半.我们把下面移动的圆,叫做mMoveCircle. 这样一画,就很简单明了了对不对.只要在拖动的时候

【Android UI设计与开发】第09期:底部菜单栏(四)Fragment+PopupWindow仿QQ空间最新版底部菜单栏

转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9023451          在今天的这篇文章当中,我依然会以实战加理论结合的方式教大家如何设计出自己觉得很炫的UI界面.好的,话不多说,进入正题.今天的这篇文章主要是以仿QQ空间的底部菜单栏效果为主,实现的效果有: <1>实现了点击按钮时的切换图片效果: <2>实现了点击按钮时的切换界面效果: <3>实现了点击中间圆形按钮时弹出菜单以及按钮图片切

仿网易‘垃圾箱’动画效果

一说到动画,大家会说到CSS3动画,确实,本文带来一片简单的仿网易'垃圾箱'动画效果,涉及到的知识点是transform.transition transform 属性向元素应用 2D 或 3D 转换.该属性允许我们对元素进行旋转.缩放.移动或倾斜. transform: none|transform-functions; transition 属性是一个简写属性,用于设置四个过渡属性. transition: property duration timing-function delay; 首