Android 仿QQ未读消息拖拽删除粘性控件效果
2017-07-20 09:19
811 查看
效果图:
分析 一 :
1、应用的地方:如未读数据的清除等
2、这个控件要实现哪些功能呢?
1)拖拽超出范围时,断开了,此时我们松手,图标消失
2)拖拽超出范围时,断开了,此时我们把图标移动回去,图标恢复原样
3)拖拽没有超出范围时,此时我们松手,图标弹回去
3、如何实现:
1)我们先画个两个静态的圆圈,一个大的,一个小的
2)绘制中间连接的部分:
3)把静态的数值变成变量
4)不断地修改变量,重绘界面,就能动起来
分析 二 :
1、有两个小球(一个固定圆,一个动圆)
2、然后两个球之间连接(一定区域)
3、固定圆的坐标我们指定,动圆坐标根据我们的鼠标点击移动或者手指触摸移动
还有要实现的效果:
1、单击小球的时候绘制大球,大球可以随手势滑动,小球不动
2、大球和小球之间有一定的范围,在这个范围内,大球任意移动
3、超过范围,只显示大球,返回到范围内松手,恢复原来状态(未读状态)
4、超过范围,只显示大球,不返回到一定的范围内,松手,消失不见(已读状态)
好了,大致的就是这么多了,首先我们先来看下贝塞尔曲线的解释,因为在这里我们中间的连接范围用到了这个知识。我也只是大概的了解了一下,因为我们用的是已经给我们提供好的函数和接口,具体的底层怎么实现的我们就不考究了。
看下图解:(这里面的那两个蓝色的斜线之间的红色是贝塞尔曲线绘制的范围)
首先我们要自定义粘性VIew ,ViscosityView.java
创建画笔:
首先我们就来定义圆了哈,首先定义动圆和固定圆的一些用到的变量,因为我们只用把动的改成了变量,然后我们去动态的改变这些变量,然后去重绘圆,是不是可以达到了圆的运动了呢,嘿嘿:
在这里我们还有一个问题,就是当我们绘制的时候,因为有了状态栏的高度,我们的画布是我们状态栏之下的,为了大球和我们的手势是一起的,首先我们要去获取状态栏的高度:
好了,需要获取到的资源我们基本上差不多了,我们先来画圆吧:
onDraw()方法中:
到目前为止,我们只是画出了轮廓,还是没有让让根据我们的手势动起来,这里我们来实现以下,这个时候我们就要实现一下onTouch()方法了在这里我们来判断按下、移动、抬起的手势。还有就是在这里我们在移动的时候去判断是否是显示,隐藏,断开的了,代码量也不多,在这里我就不多做解释了,代码中我解释详细一下就行了.
这个时候,我们就需要改变我们onDraw()里面的方法的范围了,也就是判断
isOutToRange和isDisappear分别为true和false的了,改变如下:
工具类:
GeometryUtil.Java工具类:
Utils.java工具类:
参考:http://blog.csdn.net/wuyinlei/article/details/50634839
http://www.jb51.net/article/108265.htm http://blog.csdn.net/gesanri/article/details/48490873
http://blog.csdn.net/zhangphil/article/details/49746709 http://www.bubuko.com/infodetail-1092644.html
源码:http://download.csdn.net/detail/lijinweii/9905291
分析 一 :
1、应用的地方:如未读数据的清除等
2、这个控件要实现哪些功能呢?
1)拖拽超出范围时,断开了,此时我们松手,图标消失
2)拖拽超出范围时,断开了,此时我们把图标移动回去,图标恢复原样
3)拖拽没有超出范围时,此时我们松手,图标弹回去
3、如何实现:
1)我们先画个两个静态的圆圈,一个大的,一个小的
2)绘制中间连接的部分:
3)把静态的数值变成变量
4)不断地修改变量,重绘界面,就能动起来
分析 二 :
1、有两个小球(一个固定圆,一个动圆)
2、然后两个球之间连接(一定区域)
3、固定圆的坐标我们指定,动圆坐标根据我们的鼠标点击移动或者手指触摸移动
还有要实现的效果:
1、单击小球的时候绘制大球,大球可以随手势滑动,小球不动
2、大球和小球之间有一定的范围,在这个范围内,大球任意移动
3、超过范围,只显示大球,返回到范围内松手,恢复原来状态(未读状态)
4、超过范围,只显示大球,不返回到一定的范围内,松手,消失不见(已读状态)
好了,大致的就是这么多了,首先我们先来看下贝塞尔曲线的解释,因为在这里我们中间的连接范围用到了这个知识。我也只是大概的了解了一下,因为我们用的是已经给我们提供好的函数和接口,具体的底层怎么实现的我们就不考究了。
看下图解:(这里面的那两个蓝色的斜线之间的红色是贝塞尔曲线绘制的范围)
首先我们要自定义粘性VIew ,ViscosityView.java
/** * 自定义粘性view */ public class ViscosityView extends View { private Paint mPaint; //固定圆,并且初始化 private PointF mFixedCircle = new PointF(150f, 150f); //固定圆的半径 float mFixedRadius = 14f; //动圆 并且初始化 private PointF mDragCircle = new PointF(80f, 80f); //动圆 半径 float mDragRadius = 20f; //动圆两个焦点的坐标 private PointF[] mDragPoints; //固定圆的两个焦点坐标 private PointF[] mFixedPoints; //控制焦点 private PointF mControlPoint; //获取状态栏的高度 private int mStatusBarHeight; /** * 是否断开 */ private boolean isOutToRange = false; /** * 是否消失(是否可见) */ private boolean isDisappear = false; /** * 两个圆最远的距离 */ float farestDistance = 100f; String text = ""; /** * 设置数字 * @param num */ public void setNumber(int num) { text = String.valueOf(num); } /** * 初始化圆的圆心坐标 * @param x * @param y */ public void initCenter(float x, float y) { mDragCircle = new PointF(x, y); mFixedCircle = new PointF(x, y); mControlPoint = new PointF(x, y); invalidate(); } public void setOnDisappearListener(OnDisappearListener mListener) { this.mListener = mListener; } public void setStatusBarHeight(int statusBarHeight) { this.mStatusBarHeight = statusBarHeight; } public OnDisappearListener getOnDisappearListener() { return mListener; } interface OnDisappearListener { void onDisappear(PointF mDragCenter); void onReset(boolean isOutOfRange); } private OnDisappearListener mListener; /** * 清除 */ private void disappeared() { isDisappear = true; invalidate(); if (mListener != null) { mListener.onDisappear(mDragCircle); } } public ViscosityView(Context context) { this(context, null); } public ViscosityView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ViscosityView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /** * 创建画笔 */ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); /** * 设置画笔的颜色 */ mPaint.setColor(Color.RED); } @Override protected void onDraw(Canvas canvas) { //保持当前画布的状态 canvas.save(); //移动画布 canvas.translate(0, -mStatusBarHeight); //根据两个圆的圆心的距离获取固定圆的半径 float distance = getTempFiexdCircle(); //计算连接部分 //1、获取直线与圆的焦点 float yOffset = mFixedCircle.y - mDragCircle.y; float xOffset = mFixedCircle.x - mDragCircle.x; //获取斜率 Double lineK = null; if (xOffset != 0) { lineK = (double) yOffset / xOffset; } //通过几何工具获取焦点坐标 this.mFixedPoints = GeometryUtil.getIntersectionPoints(mFixedCircle, distance, lineK); this.mDragPoints = GeometryUtil.getIntersectionPoints(mDragCircle, mDragRadius, lineK); //2、获取控制点坐标 this.mControlPoint = GeometryUtil.getMiddlePoint(mDragCircle, mFixedCircle); if (!isDisappear) { //画拖拽圆 动圆 //canvas.drawCircle(80f,80f,20f,mPaint); canvas.drawCircle(mDragCircle.x, mDragCircle.y, mDragRadius, mPaint); if (!isOutToRange) { //画一个固定圆 //canvas.drawCircle(150f,150f,14f,mPaint); canvas.drawCircle(mFixedCircle.x, mFixedCircle.y, distance, mPaint); //画连接部分 这个是用的那个贝塞尔曲线绘制的连接部分 Path path = new Path(); //跳到某个点1 path.moveTo(mFixedPoints[0].x, mFixedPoints[0].y); //画曲线 1--->2 path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints[0].x, mDragPoints[0].y); //画直线2---->3 path.lineTo(mDragPoints[1].x, mDragPoints[1].y); //画曲线3---->4 path.quadTo(mControlPoint.x, mControlPoint.y, mFixedPoints[1].x, mFixedPoints[1].y); path.close(); canvas.drawPath(path, mPaint); } } //恢复画布 canvas.restore(); } /** * 获取临时的固定圆的半径 * @return */ private float getTempFiexdCircle() { //获取到两个圆心之间的距离 float instance = GeometryUtil.getDistanceBetween2Points(mDragCircle, mFixedCircle); //这个是在两个圆之间的实际距离和我们定义的距离之间取得最小值 instance = Math.min(instance, farestDistance); //0.0f--->1.0f>>>>>1.0f---》0.0f float percent = instance / farestDistance; //估值器 return evaluate(percent, mFixedRadius, mFixedRadius * 0.2); } /** * 估值器 * @param fraction * @param startValue * @param endValue * @return */ public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); } /** * 重写这个方法,让小球动起来 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { float x = 0; float y = 0; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //获取到按下的时候的坐标(因为我们已经把画布往上移动了状态栏的高度了,或者是我们在这里做判断) x = event.getRawX(); y = event.getRawY(); isDisappear = false; isOutToRange = false; //更新动圆的坐标 updataDragCircle(x, y); break; case MotionEvent.ACTION_MOVE: //移动的时候获取坐标 x = event.getRawX(); y = event.getRawY(); //更新动圆的坐标 updataDragCircle(x, y); //处理断开 float distance = GeometryUtil.getDistanceBetween2Points(mDragCircle, mFixedCircle); if (distance > farestDistance) { //如果获取到的距离大于我们定义的最大的距离 isOutToRange = true; //断开设置为true invalidate(); //重绘 return false; } break; case MotionEvent.ACTION_UP: if (isOutToRange) { //如果是断开 isOutToRange = false; //设置为false ec2b //处理断开 float d = GeometryUtil.getDistanceBetween2Points(mDragCircle, mFixedCircle); if (d > farestDistance) { // * a、拖拽超出范围,断开-->松手-->消失 //松手还没有放回去 //isDisappear = true; disappeared(); //重绘一下 invalidate(); } else { // * b、拖拽超出范围,断开---->放回去了--->恢复 updataDragCircle(mFixedCircle.x, mFixedCircle.y); isDisappear = false; if (mListener != null) mListener.onReset(isOutToRange); } } else { final PointF tempDragCircle = new PointF(mDragCircle.x, mDragCircle.y); // * c、拖拽没有超出范围,断开--->恢复 final ValueAnimator mAnim = ValueAnimator.ofFloat(1.0f); mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = mAnim.getAnimatedFraction(); PointF p = GeometryUtil.getPointByPercent(tempDragCircle, mFixedCircle, percent); updataDragCircle(p.x, p.y); } }); //差之器 mAnim.setInterpolator(new OvershootInterpolator(4)); mAnim.setDuration(500); mAnim.start(); } break; default: isOutToRange = false; break; } return true; } /** * 更新拖拽圆的圆心坐标 * @param rawX * @param rawY */ private void updataDragCircle(float rawX, float rawY) { //更新的坐标 mDragCircle.set(rawX, rawY); invalidate(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //获取状态栏的高度 mStatusBarHeight = Utils.getStatusBarHeight(this); } }分析下这个ViscosityView.java
创建画笔:
public ViscosityView(Context context) { this(context, null); } public ViscosityView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public ViscosityView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); /** * 创建画笔 */ mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); /** * 设置画笔的颜色 */ mPaint.setColor(Color.RED); }我们这个时候先来画圆:
首先我们就来定义圆了哈,首先定义动圆和固定圆的一些用到的变量,因为我们只用把动的改成了变量,然后我们去动态的改变这些变量,然后去重绘圆,是不是可以达到了圆的运动了呢,嘿嘿:
private Paint mPaint; //固定圆,并且初始化 private PointF mFixedCircle = new PointF(150f, 150f); //固定圆的半径 float mFixedRadius = 14f; //动圆 并且初始化 private PointF mDragCircle = new PointF(80f, 80f); //动圆 半径 float mDragRadius = 20f; //动圆两个焦点的坐标 private PointF[] mDragPoints; //固定圆的两个焦点坐标 private PointF[] mFixedPoints; //控制焦点 private PointF mControlPoint;
在这里我们还有一个问题,就是当我们绘制的时候,因为有了状态栏的高度,我们的画布是我们状态栏之下的,为了大球和我们的手势是一起的,首先我们要去获取状态栏的高度:
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //获取状态栏的高度 mStatusBarHeight = Utils.getStatusBarHeight(this); }重写onDraw()(onDraw()里面写):
//保持当前画布的状态 canvas.save(); //移动画布 canvas.translate(0, -mStatusBarHeight);在这里我们先把两个圆之间的距离给获取到:
/** * 获取临时的固定圆的半径 * @return */ private float getTempFiexdCircle() { //获取到两个圆心之间的距离 float instance = GeometryUtil.getDistanceBetween2Points(mDragCircle, mFixedCircle); //这个是在两个圆之间的实际距离和我们定义的距离之间取得最小值 instance = Math.min(instance, farestDistance); //0.0f--->1.0f>>>>>1.0f---》0.0f float percent = instance / farestDistance; //估值器 return evaluate(percent, mFixedRadius, mFixedRadius * 0.2); } /** * 估值器 * @param fraction * @param startValue * @param endValue * @return */ public Float evaluate(float fraction, Number startValue, Number endValue) { float startFloat = startValue.floatValue(); return startFloat + fraction * (endValue.floatValue() - startFloat); }
好了,需要获取到的资源我们基本上差不多了,我们先来画圆吧:
onDraw()方法中:
//根据两个圆的圆心的距离获取固定圆的半径 float distance = getTempFiexdCircle(); //计算连接部分 //1、获取直线与圆的焦点 float yOffset = mFixedCircle.y - mDragCircle.y; float xOffset = mFixedCircle.x - mDragCircle.x; /** * 获取斜率 */ Double lineK = null; if (xOffset != 0) { lineK = (double) yOffset / xOffset; } //通过几何工具获取焦点坐标 this.mFixedPoints = GeometryUtil.getIntersectionPoints(mFixedCircle, distance, lineK); this.mDragPoints = GeometryUtil.getIntersectionPoints(mDragCircle, mDragRadius, lineK); //2、获取控制点坐标 this.mControlPoint = GeometryUtil.getMiddlePoint(mDragCircle, mFixedCircle); //绘制动圆 canvas.drawCircle(mDragCircle.x, mDragCircle.y, mDragRadius, mPaint); //画一个固定圆 //canvas.drawCircle(150f,150f,14f,mPaint); canvas.drawCircle(mFixedCircle.x, mFixedCircle.y, distance, mPaint); //canvas.drawCircle(150f,150f,14f,mPaint); canvas.drawCircle(mFixedCircle.x, mFixedCircle.y, distance, mPaint); //画连接部分 这个是用的那个贝塞尔曲线绘制的连接部分 Path path = new Path(); //跳到某个点1 path.moveTo(mFixedPoints[0].x, mFixedPoints[0].y); //画曲线 1--->2 path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints[0].x, mDragPoints[0].y); //画直线2---->3 path.lineTo(mDragPoints[1].x, mDragPoints[1].y); //画曲线3---->4 path.quadTo(mControlPoint.x, mControlPoint.y, mFixedPoints[1].x, mFixedPoints[1].y); path.close(); canvas.drawPath(path, mPaint); //恢复画布 canvas.restore();现在应该可以画出了两个圆还有就是两个圆之间的范围了如图所示:
到目前为止,我们只是画出了轮廓,还是没有让让根据我们的手势动起来,这里我们来实现以下,这个时候我们就要实现一下onTouch()方法了在这里我们来判断按下、移动、抬起的手势。还有就是在这里我们在移动的时候去判断是否是显示,隐藏,断开的了,代码量也不多,在这里我就不多做解释了,代码中我解释详细一下就行了.
/** * 重写这个方法,让小球动起来 * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { float x = 0; float y = 0; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: //获取到按下的时候的坐标(因为我们已经把画布往上移动了状态栏的高度了,或者是我们在这里做判断) x = event.getRawX(); y = event.getRawY(); isDisappear = false; isOutToRange = false; //更新动圆的坐标 updataDragCircle(x, y); break; case MotionEvent.ACTION_MOVE: //移动的时候获取坐标 x = event.getRawX(); y = event.getRawY(); //更新动圆的坐标 updataDragCircle(x, y); //处理断开 float distance = GeometryUtil.getDistanceBetween2Points(mDragCircle, mFixedCircle); if (distance > farestDistance) { //如果获取到的距离大于我们定义的最大的距离 isOutToRange = true; //断开设置为true invalidate(); //重绘 return false; } break; case MotionEvent.ACTION_UP: if (isOutToRange) { //如果是断开 isOutToRange = false; //设置为false //处理断开 float d = GeometryUtil.getDistanceBetween2Points(mDragCircle, mFixedCircle); if (d > farestDistance) { // * a、拖拽超出范围,断开-->松手-->消失 //松手还没有放回去 //isDisappear = true; disappeared(); //重绘一下 invalidate(); } else { // * b、拖拽超出范围,断开---->放回去了--->恢复 updataDragCircle(mFixedCircle.x, mFixedCircle.y); isDisappear = false; if (mListener != null) mListener.onReset(isOutToRange); } } else { final PointF tempDragCircle = new PointF(mDragCircle.x, mDragCircle.y); // * c、拖拽没有超出范围,断开--->恢复 final ValueAnimator mAnim = ValueAnimator.ofFloat(1.0f); mAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = mAnim.getAnimatedFraction(); PointF p = GeometryUtil.getPointByPercent(tempDragCircle, mFixedCircle, percent); updataDragCircle(p.x, p.y); } }); //差之器 mAnim.setInterpolator(new OvershootInterpolator(4)); mAnim.setDuration(500); mAnim.start(); } break; default: isOutToRange = false; break; } return true; } /** * 更新拖拽圆的圆心坐标 * @param rawX * @param rawY */ private void updataDragCircle(float rawX, float rawY) { //更新的坐标 mDragCircle.set(rawX, rawY); invalidate(); }
这个时候,我们就需要改变我们onDraw()里面的方法的范围了,也就是判断
isOutToRange和isDisappear分别为true和false的了,改变如下:
@Override protected void onDraw(Canvas canvas) { //保持当前画布的状态 canvas.save(); //移动画布 canvas.translate(0, -mStatusBarHeight); //根据两个圆的圆心的距离获取固定圆的半径 float distance = getTempFiexdCircle(); //计算连接部分 //1、获取直线与圆的焦点 float yOffset = mFixedCircle.y - mDragCircle.y; float xOffset = mFixedCircle.x - mDragCircle.x; //获取斜率 Double lineK = null; if (xOffset != 0) { lineK = (double) yOffset / xOffset; } //通过几何工具获取焦点坐标 this.mFixedPoints = GeometryUtil.getIntersectionPoints(mFixedCircle, distance, lineK); this.mDragPoints = GeometryUtil.getIntersectionPoints(mDragCircle, mDragRadius, lineK); //2、获取控制点坐标 this.mControlPoint = GeometryUtil.getMiddlePoint(mDragCircle, mFixedCircle); if (!isDisappear) { //画拖拽圆 动圆 //canvas.drawCircle(80f,80f,20f,mPaint); canvas.drawCircle(mDragCircle.x, mDragCircle.y, mDragRadius, mPaint); if (!isOutToRange) { //画一个固定圆 //canvas.drawCircle(150f,150f,14f,mPaint); canvas.drawCircle(mFixedCircle.x, mFixedCircle.y, distance, mPaint); //画连接部分 这个是用的那个贝塞尔曲线绘制的连接部分 Path path = new Path(); //跳到某个点1 path.moveTo(mFixedPoints[0].x, mFixedPoints[0].y); //画曲线 1--->2 path.quadTo(mControlPoint.x, mControlPoint.y, mDragPoints[0].x, mDragPoints[0].y); //画直线2---->3 path.lineTo(mDragPoints[1].x, mDragPoints[1].y); //画曲线3---->4 path.quadTo(mControlPoint.x, mControlPoint.y, mFixedPoints[1].x, mFixedPoints[1].y); path.close(); canvas.drawPath(path, mPaint); } } //恢复画布 canvas.restore(); }好了,我们来看下实现的动画效果:
工具类:
GeometryUtil.Java工具类:
package vp.zyqj.zz.viscositypoint; import android.graphics.PointF; /** * 几何图形工具 */ public class GeometryUtil { /** * As meaning of method name. * 获得两点之间的距离 * @param p0 * @param p1 * @return */ public static float getDistanceBetween2Points(PointF p0, PointF p1) { float distance = (float) Math.sqrt(Math.pow(p0.y - p1.y, 2) + Math.pow(p0.x - p1.x, 2)); return distance; } /** * Get middle point between p1 and p2. * 获得两点连线的中点 * @param p1 * @param p2 * @return */ public static PointF getMiddlePoint(PointF p1, PointF p2) { return new PointF((p1.x + p2.x) / 2.0f, (p1.y + p2.y) / 2.0f); } /** * Get point between p1 and p2 by percent. * 根据百分比获取两点之间的某个点坐标 * @param p1 * @param p2 * @param percent * @return */ public static PointF getPointByPercent(PointF p1, PointF p2, float percent) { return new PointF(evaluateValue(percent, p1.x , p2.x), evaluateValue(percent, p1.y , p2.y)); } /** * 根据分度值,计算从start到end中,fraction位置的值。fraction范围为0 -> 1 * @param fraction * @param start * @param end * @return */ public static float evaluateValue(float fraction, Number start, Number end){ return start.floatValue() + (end.floatValue() - start.floatValue()) * fraction; } /** * Get the point of intersection between circle and line. * 获取 通过指定圆心,斜率为lineK的直线与圆的交点。 * * @param pMiddle The circle center point. * @param radius The circle radius. * @param lineK The slope of line which cross the pMiddle. * @return */ public static PointF[] getIntersectionPoints(PointF pMiddle, float radius, Double lineK) { PointF[] points = new PointF[2]; float radian, xOffset = 0, yOffset = 0; if(lineK != null){ radian= (float) Math.atan(lineK); xOffset = (float) (Math.sin(radian) * radius); yOffset = (float) (Math.cos(radian) * radius); }else { xOffset = radius; yOffset = 0; } points[0] = new PointF(pMiddle.x + xOffset, pMiddle.y - yOffset); points[1] = new PointF(pMiddle.x - xOffset, pMiddle.y + yOffset); return points; } }
Utils.java工具类:
package vp.zyqj.zz.viscositypoint; import android.content.Context; import android.graphics.Rect; import android.support.v4.view.MotionEventCompat; import android.util.DisplayMetrics; import android.util.TypedValue; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; public class Utils { public static Toast mToast; public static void showToast(Context mContext, String msg) { if (mToast == null) { mToast = Toast.makeText(mContext, "", Toast.LENGTH_SHORT); } mToast.setText(msg); mToast.show(); } /** * dip 转换成 px * @param dip * @param context * @return */ public static float dip2Dimension(float dip, Context context) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, displayMetrics); } /** * @param dip * @param context * @param complexUnit {@link TypedValue#COMPLEX_UNIT_DIP} {@link TypedValue#COMPLEX_UNIT_SP}} * @return */ public static float toDimension(float dip, Context context, int complexUnit) { DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); return TypedValue.applyDimension(complexUnit, dip, displayMetrics); } /** 获取状态栏高度 * @param v * @return */ public static int getStatusBarHeight(View v) { if (v == null) { return 0; } Rect frame = new Rect(); v.getWindowVisibleDisplayFrame(frame); return frame.top; } public static String getActionName(MotionEvent event) { String action = "unknow"; switch (MotionEventCompat.getActionMasked(event)) { case MotionEvent.ACTION_DOWN: action = "ACTION_DOWN"; break; case MotionEvent.ACTION_MOVE: action = "ACTION_MOVE"; break; case MotionEvent.ACTION_UP: action = "ACTION_UP"; break; case MotionEvent.ACTION_CANCEL: action = "ACTION_CANCEL"; break; case MotionEvent.ACTION_SCROLL: action = "ACTION_SCROLL"; break; case MotionEvent.ACTION_OUTSIDE: action = "ACTION_SCROLL"; break; default: break; } return action; } }
参考:http://blog.csdn.net/wuyinlei/article/details/50634839
http://www.jb51.net/article/108265.htm http://blog.csdn.net/gesanri/article/details/48490873
http://blog.csdn.net/zhangphil/article/details/49746709 http://www.bubuko.com/infodetail-1092644.html
源码:http://download.csdn.net/detail/lijinweii/9905291
相关文章推荐
- Android仿QQ未读消息拖拽删除粘性效果
- 仿QQ未读消息拖拽删除粘性效果
- android自定义view之模拟qq消息拖拽删除效果
- android仿QQ消息列表拖拽气泡效果源码读后感(1)
- 仿qq安卓客户端实现消息数目手势拖拽删除效果
- Android基础控件——RecyclerView实现拖拽排序侧滑删除效果
- Android开发学习之仿手机QQ消息列表侧滑删除效果
- Android仿QQ消息列表ListView滑动删除效果
- Android贝塞尔曲线初步学习第二课 仿QQ未读消息气泡拖拽黏连效果
- qq列表拖拽效果 qq果冻效果 qq删除消息提醒 小红点 CAShapeLayer动画
- android实现QQ未读消息拖拽动态效果
- Android仿QQ未读消息--红点拖拽删除【源代码】
- Android仿QQ消息粘性球控件
- Android开发之QQ黏性控件(QQ消息未读提醒,在固定范围内,拖拽回弹,超出范围,松手消失)
- 仿android手机qq消息列表中删除按钮效果
- Android使用贝塞尔线高仿QQ聊天消息气泡的拖拽效果
- Android 自定义实现类似QQ消息贝塞尔拖拽效果BezierView
- android 仿qq5.0 消息气泡拖动删除效果
- [Android]仿新版QQ的tab下面拖拽标记为已读的效果
- 仿QQ未读消息拖拽效果