项目需求想要做一个页面的小挂件,实现类似窗帘的效果,去网上找资料,看到了这个:
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
网友评论