美文网首页
Android ViewDragHelper实现窗帘效果小挂件

Android ViewDragHelper实现窗帘效果小挂件

作者: 水言 | 来源:发表于2017-07-21 14:16 被阅读147次

项目需求想要做一个页面的小挂件,实现类似窗帘的效果,去网上找资料,看到了这个:
Android 窗帘效果
实现的挺好的,但是我们的需求是全屏展开,然后展开后需要通过页面边界触摸关闭。
关于边界的触摸效果想到了官方出了DrawerLayout,它就是通过边界触摸打开一个抽屉效果页面的。
android官方侧滑菜单DrawerLayout详解
看了一会儿源码发现DrawerLayout中实现边界触摸的的部分就是由ViewDragHelper实现的,于是就想自己动手试试。

DEMO

ViewDragHelper的实例创建

mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelperCallBack());
mDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_BOTTOM);

1.通过工厂模式创建的对象,第一个参数是需要监控的父布局,自定义View中一般就是自己;第二个参数是ViewDragHelper对触摸事件的敏感程度,默认1,越大越敏感;第三个是ViewDragHelper处理触摸事件后的回调。

自定义View的大小和位置控制

重写onMeasure

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        //frameLayout就按父布局的大小去测绘
        measureChild(frameLayout,widthMeasureSpec,heightMeasureSpec);
        //绳子按照图片大小从新测量大小
        imgWidth=imgRope.getDrawable().getIntrinsicWidth();
        imgHeight=imgRope.getDrawable().getIntrinsicHeight();
        measureChild(imgRope,MeasureSpec.makeMeasureSpec(imgWidth, MeasureSpec.UNSPECIFIED),MeasureSpec.makeMeasureSpec(imgHeight, MeasureSpec.UNSPECIFIED));
    }

重写onLayout

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        //设置整个控件的高度
        MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
        mlp.height = mScreenHeigh + imgWidth;
        setLayoutParams(mlp);
        //mCurTop是滑动的时候距顶部的距离
        frameLayout.layout(0, -mScreenHeigh + mCurTop, mScreenWidth, mCurTop);
        imgRope.layout(imgPosX, mCurTop,
                imgPosX+imgWidth+imgRope.getPaddingRight()+imgRope.getPaddingRight(),
                imgHeight + mCurTop+imgRope.getPaddingBottom()
        );
}

重写ViewDragHelperCallBack

private class ViewDragHelperCallBack extends ViewDragHelper.Callback {
        @Override
        public boolean tryCaptureView(View child, int pointerId) {
            if(isOpen){//根据是否开关,返回ture则表示可以捕获该view
                return child==frameLayout;
            }
            else{
                return child == imgRope;
            }
        }
      //边缘触摸
        @Override
        public void onEdgeDragStarted(int edgeFlags, int pointerId) {
            if(isOpen){
                mDragHelper.captureChildView(frameLayout, pointerId);
            }
            else{
                mDragHelper.captureChildView(imgRope, pointerId);
            }
        }
        @Override
        public int clampViewPositionHorizontal(View child, int left, int dx) {
            if(child==imgRope){
                return imgPosX;
            }
            return super.clampViewPositionHorizontal(child, left, dx);
        }
        @Override
        public int clampViewPositionVertical(View child, int top, int dy) {
            if(child==imgRope) {
                return Math.min(Math.max(top, 0), mScreenHeigh);
            }
            else{
                return Math.max(Math.min(top, 0), -mScreenHeigh);
            }
        }
        @Override
        public void onViewReleased(View releasedChild, float xvel, float yvel) {
            //手指释放时回调
            float movePrecent  = Math.abs(releasedChild.getTop()) / (float) mScreenHeigh;;
            int finalTop=0;
            if(releasedChild==imgRope) {
                finalTop = (yvel >= 100 ||movePrecent > 0.3f) ? mScreenHeigh : 0;
                mDragHelper.settleCapturedViewAt(imgPosX, finalTop);
            }
            else{
                finalTop = (Math.abs(yvel)>= 100 || movePrecent > 0.3f) ?-mScreenHeigh:0 ;
                mDragHelper.settleCapturedViewAt(0, finalTop);
            }
            invalidate();
        }
       //滑动位置变化的时候
        @Override
        public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
            if(changedView==imgRope) {
                mCurTop = top;
            }
            else{
                mCurTop=mScreenHeigh+top;
            }
            requestLayout();
        }
        @Override
        public int getViewVerticalDragRange(View child) {
            if (child == imgRope) {
                return getMeasuredHeight() - child.getMeasuredHeight();
            }
            return super.getViewVerticalDragRange(child);
        }
    }

重写触摸事件

     //触摸区域判断方法
    private boolean isTouchPointInView(View view, int x, int y) {
        if (view == null) {
            return false;
        }
        int[] location = new int[2];
        view.getLocationOnScreen(location);
        int left = location[0];
        int top = location[1];
        int right = left + view.getMeasuredWidth();
        int bottom = top + view.getMeasuredHeight();
        return y >= top && y <= bottom && x >= left && x <= right;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //判断是否是触摸到绳子,如果是绳子,继续拦截触摸事件
        if (ev.getAction() == MotionEvent.ACTION_DOWN || ev.getAction() == MotionEvent.ACTION_MOVE) {
            imgTouch = isTouchPointInView(imgRope, (int) ev.getX(), (int) ev.getY());
        } else {
            imgTouch = false;
        }
             //如果触摸的是绳子或者已经开着了继续拦截触摸事件
        if (isOpen || imgTouch) {
            return mDragHelper.shouldInterceptTouchEvent(ev);
        }
        return super.onInterceptTouchEvent(ev);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (isOpen || imgTouch) {
            mDragHelper.processTouchEvent(event);
            return true;
        }
        return super.onTouchEvent(event);
    }
    @Override
    public void computeScroll() {
        if (mDragHelper.continueSettling(true)) {
            invalidate();
        }
    }

项目地址:链接:http://pan.baidu.com/s/1eRDNYim 密码:e81u

参考:
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0911/1680.html
http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2014/0925/1713.html

相关文章

网友评论

      本文标题:Android ViewDragHelper实现窗帘效果小挂件

      本文链接:https://www.haomeiwen.com/subject/zkvscxtx.html