Android滑动删除控件

Android滑动删除控件

效果展示

代码实现

静态布局

自定义一个ViewGroup,继承至FrameLayout,覆写其中的几个关键方法,用于给其中的两个子view设置布局位置。

    private View contentView, deleteView;
    int contentViewHeight, contentViewWidth;
    int deleteViewHeight, deleteViewWidth;

    private void init() {
    }


    /**
     * 从xml中加载完布局,只知道有几个子view,并没有进行测量
     * 一般可以初始化子view的引用
     */
    @Override
    protected void onFinishInflate() {
    super.onFinishInflate();
    contentView = getChildAt(0);
    deleteView = getChildAt(1);
    }

    /**
     * 测量完子view后调用,在这里可以直接获取子view的高度
     */
    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);
    contentViewWidth = contentView.getMeasuredWidth();
    deleteViewHeight = deleteView.getMeasuredHeight();
    }


    /**
     * 放置子view到合适的位置
     */
    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    super.onLayout(changed, left, top, right, bottom);
    contentView.layout(0, 0, contentViewWidth, contentViewHeight);
    deleteView.layout(contentViewWidth, 0, contentViewWidth + deleteViewWidth,  deleteViewHeight);
    }

处理滑动逻辑

利用ViewDragHelper类封装了对触摸位置、速度、距离的检测,以及Scroller. 需要我们制定什么时候滑动,以及滑动多少。 需要把ViewGroup中受到的触摸事件传给ViewDragHelper实例。

触摸事件传给ViewDragHelper实例

       @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return mViewDragHelper.shouldInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mViewDragHelper.processTouchEvent(event);

        //消费掉此触摸事件,不向上返回
        return true;
    }

在ViewDragHelper的回调函数中处理滑动逻辑。

    private ViewDragHelper mViewDragHelper;
    private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() {

        /**
         * @return 返回true表示获得view的控制权
         */
        @Override
        public boolean tryCaptureView(View view, int i) {
            return view == contentView || view == deleteView;
        }

        @Override
        public void onViewCaptured(View capturedChild, int activePointerId) {
            super.onViewCaptured(capturedChild, activePointerId);
        }

        /**
         * 控制view在水平方向上实际滑动了多少
         * @param child 当前触摸的view
         * @param left view的左边坐标,负数表示view的左边超出父view边界的长度
         * @param dx
         * @return 返回多少,代表想让child的left=多少
         */
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            Log.i(TAG, "clampViewPositionHorizontal-->" + "left=" + left);
            if (child == contentView) {
                if (left > 0) left = 0;
                if (left < -deleteViewWidth) left = -deleteViewWidth;
            } else if (child == deleteView) {
                //使deleteVie不会超出指定的边界
                if (left < contentViewWidth - deleteViewWidth) {
                    left = contentViewWidth - deleteViewWidth;
                }
            }
            return left;
        }

        /**
         * 水平方向拖拽的范围
         */
        @Override
        public int getViewHorizontalDragRange(View child) {
            return super.getViewHorizontalDragRange(child);
        }

        /**
         * view滑动后的回调
         * @param changedView
         * @param left
         * @param top
         * @param dx   x轴方向的改编值
         * @param dy
         */
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            super.onViewPositionChanged(changedView, left, top, dx, dy);
            Log.i(TAG, "onViewPositionChanged-->" + "dx=" + dx);
            //重新布局子view的位置
            if (changedView == contentView) {
                deleteView.layout(deleteView.getLeft() + dx, 0, deleteView.getRight() + dx, deleteView.getBottom());
            } else if (changedView == deleteView) {
                contentView.layout(contentView.getLeft() + dx, 0, contentView.getRight() + dx, contentView.getBottom());
            }
        }

        /**
         * TouchUp的回调
         * @param releasedChild
         * @param xvel
         * @param yvel
         */
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            super.onViewReleased(releasedChild, xvel, yvel);

            if (contentView.getLeft() < -deleteViewWidth / 2) {   //滑动条打开状态
                mViewDragHelper.smoothSlideViewTo(contentView, -deleteViewWidth, 0);
            } else {          //滑动条关闭状态
                mViewDragHelper.smoothSlideViewTo(contentView, 0, 0);
            }
            //
            ViewCompat.postInvalidateOnAnimation(SwipeView.this);  //动画刷新
        }
    };

动画效果

Scroller帮助计算好view在某个时间点会处于某个位置,达到动画的效果

    @Override
    public void computeScroll() {
        super.computeScroll();
        if(mViewDragHelper.continueSettling(true)){     //内部有Scroller计算位置和移动
            ViewCompat.postInvalidateOnAnimation(SwipeView.this);       //刷新当前view
        }

    }

ListView中的滑动删除效果

完整代码

github

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程之路

羊皮书APP(Android版)开发系列(十九)在ScrollView中使用ListView、GridView的方法

952
来自专栏学海无涯

Android开发之ViewPager+Fragment+FragmentTabHost实现底部菜单

在Android开发中,底部菜单是经常要使用的,如微信、微博、支付宝等,实现底部菜单有好几种方式,大致分为: 通过TabWidget实现 隐藏TabWidget...

4944
来自专栏Android干货园

Android 关于GridView那些事

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/50...

901
来自专栏Android干货

安卓开发_九宫格布局

2903
来自专栏Android干货园

Android自定义View之TitleBar,通用标题栏

版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/49...

2322
来自专栏李蔚蓬的专栏

自定义控件基础 之 3.4 ViewGroup的测量 & 3.5 ViewGroup的绘制

之前分析中说了,ViewGroup会去管理其子View,其中一个管理项目就是负责子View的显示大小。当ViewGroup的大小为wrap_content时,V...

982
来自专栏三好码农的三亩自留地

教你搞定Android自定义ViewGroup

我们知道ViewGroup就是View的容器类,我们经常用的LinearLayout,RelativeLayout等都是ViewGroup的子类,因为ViewG...

801
来自专栏everhad

[BOT]自定义ViewPagerStripIndicator

效果图 app中下面这样的控件很常见,像默认的TabHost表现上不够灵活,下面就简单写一个可以结合ViewPager切换内容显示,提供底部“滑动条”指示所显示...

2235
来自专栏郭霖

Android 3D滑动菜单完全解析,实现推拉门式的立体特效

在上一篇文章中,我们学习了Camera的基本用法,并借助它们编写了一个例子,实现了类似于API Demos里的图片中轴旋转功能。不过那个例子的核心代码是来自于A...

36310
来自专栏Android开发与分享

【Android】造轮子:轮播图

4285

扫码关注云+社区

领取腾讯云代金券