Android(安卓)ViewDragHelper实现窗帘效果小挂件
16lz
2021-01-26
项目需求想要做一个页面的小挂件,实现类似窗帘的效果,去网上找资料,看到了这个:
Android 窗帘效果
实现的挺好的,但是我们的需求是全屏展开,然后展开后需要通过页面边界触摸关闭。
关于边界的触摸效果想到了官方出了DrawerLayout,它就是通过边界触摸打开一个抽屉效果页面的。
android官方侧滑菜单DrawerLayout详解
看了一会儿源码发现DrawerLayout中实现边界触摸的的部分就是由ViewDragHelper实现的,于是就想自己动手试试。
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视图控件架构分析之View、ViewGroup
- 网络获取图片的方法的重写--较简洁(如果手机缓存里面有就从缓存
- android 触摸点在屏幕中的坐标与bitmap在屏幕中坐标的比较
- 适用于各种连锁企业15寸多点触摸android收款机消费机pos机
- Android(安卓)让人又爱又恨的触摸机制(二)
- Android中的WebView的使用
- [Android] 滑动操作的原理及处理
- android 2.0发布
- 多点触摸测试