先给大家展示下效果图:
代码已上传至Github:高仿QQ小红点,如对您有帮助,欢迎星~感谢
绘制贝塞尔曲线:
主要是当在一定范围内拖拽时算出固定圆和拖拽圆的外切直线以及对应的切点,就可以通过path.quadTo()来绘制二阶贝塞尔曲线了~
1,当小红点静止时,什么都不做,只需要给自定义小红点QQBezierView(延伸TextView)添加一个。9文件当背景即可
2,当滑动时,通过getRootView()获得顶级根视图,然后新的一个DragView(扩展视图)来绘制各种状态时的小红点,并且通过getRootView () .addView()的方式把DragView加进去,这样DragView就可以实现全屏滑动了
自定义QQBezierView(延伸TextView)并复写onTouchEvent来处理各种情况,代码如下:
@Override 公共布尔> 私人int mState;//当前红点的状态 私有静态最终int STATE_INIT=0;//默认静止状态 私有静态最终int STATE_DRAG=1;//拖拽状态 私有静态最终int STATE_MOVE=2;//移动状态 私有静态最终int STATE_DISMISS=3;//消失状态
首先声明了小红点的四种状态,静止状态,拖拽状态,移动状态和消失状态。
在QQBezierView的onTouchEvent向下的事件中调用了setStickyPoint()方法:
/* * *设置固定圆的圆心和半径 * @param stickyX固定圆的X坐标 * @param stickyY固定圆的Y坐标 */公共空setStickyPoint (stickyX浮动,浮动stickyY touchX浮动,浮动敏感){//分别设置固定圆和拖拽圆的坐标 stickyPointF。集(stickyX stickyY); dragPointF。集(touchX、敏感);//通过两个圆点算出圆心距,也是拖拽的距离 dragDistance=MathUtil。getTwoPointDistance (dragPointF stickyPointF); 如果(dragDistance & lt;=maxDistance) {//如果拖拽距离小于规定最大距离,则固定的圆应该越来越小,这样看着才符合实际 stickRadius=(int) (defaultRadius - dragDistance/10) & lt;10 & # 63;10:(int) (defaultRadius - dragDistance/10); mState=STATE_DRAG; 其他}{ mState=STATE_INIT; } }
接着,在QQBezierView的onTouchEvent的移动事件中调用了setDragViewLocation()方法:
/* * *设置拖拽的坐标位置 * * @param touchX拖拽时的X坐标 * @param敏感的拖拽时的Y坐标 */公共空间setDragViewLocation (touchX浮动,浮动敏感){ dragPointF。集(touchX、敏感);//随时更改圆心距 dragDistance=MathUtil。getTwoPointDistance (dragPointF stickyPointF); 如果(mState==STATE_DRAG) { 如果(isInsideRange ()) { stickRadius=(int) (defaultRadius - dragDistance/10) & lt;10 & # 63;10:(int) (defaultRadius - dragDistance/10); 其他}{ mState=STATE_MOVE; 如果(onDragListener !=null) {> 公共空间setDragUp () { 如果(mState==STATE_DRAG,,isInsideRange ()) {//拖拽状态且在范围之内 startResetAnimator (); }else if (mState==STATE_MOVE) { 如果(isInsideRange ()) {//在范围之内需要重置 startResetAnimator (); 其他}{//在范围之外消失动画 mState=STATE_DISMISS; startExplodeAnim (); } } }
最后来看下DragView的onDraw方法,拖拽时的贝塞尔曲线以及拖拽滑动时的状态都是通过onDraw实现的:
@Override 保护无效onDraw(帆布画布){ 如果(isInsideRange (),,mState==STATE_DRAG) { mPaint.setColor (Color.RED);//绘制固定的小圆 canvas.drawCircle (stickyPointF。x, stickyPointF。y, stickRadius mPaint);//首先获得两圆心之间的斜率 链接=MathUtil浮动。getLineSlope (dragPointF stickyPointF);//然后通过两个圆心和半径,斜率来获得外切线的切点 PointF [] stickyPoints=MathUtil。getIntersectionPoints (stickyPointF stickRadius链接); dragRadius=(int)数学。分钟(mWidth mHeight)/2; PointF [] dragPoints=MathUtil。getIntersectionPoints (dragPointF dragRadius链接); mPaint.setColor (Color.RED);//二阶贝塞尔曲线的控制点取得两圆心的中点 controlPoint=MathUtil。getMiddlePoint (dragPointF stickyPointF);//绘制贝塞尔曲线 mPath.reset (); mPath.moveTo (stickyPoints [0]。x, stickyPoints [0] .y); mPath.quadTo (controlPoint。x, controlPoint。y, dragPoints [0]。x, dragPoints [0] .y); mPath.lineTo (dragPoints [1]。x, dragPoints [1] .y); mPath.quadTo (controlPoint。x, controlPoint。y, stickyPoints [1]。x, stickyPoints [1] .y); mPath.lineTo (stickyPoints [0]。x, stickyPoints [0] .y); 画布。drawPath (mPath mPaint); } 如果(mCacheBitmap !=零,,mState !=STATE_DISMISS) {//绘制缓存的位图 画布。drawBitmap (mCacheBitmap dragPointF。x - mWidth/2, dragPointF。y - mHeight/2, mPaint); } 如果(mState==STATE_DISMISS,,explodeIndex & lt;explode_res.length) {//绘制小红点消失时的爆炸动画 画布。dragPointF drawBitmap(位图(explodeIndex)。x - mWidth/2, dragPointF。y - mHeight/2, mPaint); } }Android高仿QQ小红点功能