先给大家展示下效果图:
代码已上传至Github:*QQ小红点,如对您有帮助,欢迎star~感谢
绘制贝塞尔曲线:
主要是当在一定范围内拖拽时算出固定圆和拖拽圆的外切直线以及对应的切点,就可以通过path.quadTo()来绘制二阶贝塞尔曲线了~
整体思路:
1、当小红点静止时,什么都不做,只需要给自定义小红点QQBezierView(extends TextView)添加一个.9文件当背景即可
2、当滑动时,通过getRootView()获得顶根View,然后new一个DragView ( extends View ) 来绘制各种状态时的小红点,并且通过getRootView().addView()的方式把DragView 加进去,这样DragView 就可以实现全屏滑动了
实现过程:
自定义QQBezierView ( extends TextView ) 并复写onTouchEvent来处理各种情况,代码如下:
@Override
public boolean onTouchEvent(MotionEvent event) {
//获得根View
View rootView = getRootView();
//获得触摸位置在全屏所在位置
float mRawX = event.getRawX();
float mRawY = event.getRawY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//请求父View不拦截
getParent().requestDisallowInterceptTouchEvent(true);
//获得当前View在屏幕上的位置
int[] cLocation = new int[2];
getLocationOnScreen(cLocation);
if (rootView instanceof ViewGroup) {
//初始化拖拽时显示的View
dragView = new DragView(getContext());
//设置固定圆的圆心坐标
dragView.setStickyPoint(cLocation[0] + mWidth / 2, cLocation[1] + mHeight / 2, mRawX, mRawY);
//获得缓存的bitmap,滑动时直接通过drawBitmap绘制出来
setDrawingCacheEnabled(true);
Bitmap bitmap = getDrawingCache();
if (bitmap != null) {
dragView.setCacheBitmap(bitmap);
//将DragView添加到RootView中,这样就可以全屏滑动了
((ViewGroup) rootView).addView(dragView);
setVisibility(INVISIBLE);
}
}
break;
case MotionEvent.ACTION_MOVE:
//请求父View不拦截
getParent().requestDisallowInterceptTouchEvent(true);
if (dragView != null) {
//更新DragView的位置
dragView.setDragViewLocation(mRawX, mRawY);
}
break;
case MotionEvent.ACTION_UP:
getParent().requestDisallowInterceptTouchEvent(false);
if (dragView != null) {
//手抬起时来判断各种情况
dragView.setDragUp();
}
break;
}
return true;
}
上面代码注释已经很详细了,总结一下就是通过内部拦截法来请求父View是否拦截分发事件,并通过event.getRawX()和event.getRawY()来不断更新DragView的位置,那么DragView都做了哪些事呢,接下来就看一下DragView,DragView是QQBezierView 的一个内部View类:
private int mState;//当前红点的状态 private static final int STATE_INIT = 0;//默认静止状态 private static final int STATE_DRAG = 1;//拖拽状态 private static final int STATE_MOVE = 2;//移动状态 private static final int STATE_DISMISS = 3;//消失状态
首先声明了小红点的四种状态,静止状态,拖拽状态,移动状态和消失状态。
在QQBezierView 的onTouchEvent的DOWN事件中调用了setStickyPoint()方法:
/**
* 设置固定圆的圆心和半径
* @param stickyX 固定圆的X坐标
* @param stickyY 固定圆的Y坐标
*/
public void setStickyPoint(float stickyX, float stickyY, float touchX, float touchY) {
//分别设置固定圆和拖拽圆的坐标
stickyPointF.set(stickyX, stickyY);
dragPointF.set(touchX, touchY);
//通过两个圆点算出圆心距,也是拖拽的距离
dragDistance = MathUtil.getTwoPointDistance(dragPointF, stickyPointF);
if (dragDistance <= maxDistance) {
//如果拖拽距离小于规定最大距离,则固定的圆应该越来越小,这样看着才符合实际
stickRadius = (int) (defaultRadius - dragDistance / 10) < 10 ? 10 : (int) (defaultRadius - dragDistance / 10);
mState = STATE_DRAG;
} else {
mState = STATE_INIT;
}
}
接着,在QQBezierView 的onTouchEvent的MOVE事件中调用了setDragViewLocation()方法:
/**
* 设置拖拽的坐标位置
*
* @param touchX 拖拽时的X坐标
* @param touchY 拖拽时的Y坐标
*/
public void setDragViewLocation(float touchX, float touchY) {
dragPointF.set(touchX, touchY);
//随时更改圆心距
dragDistance = MathUtil.getTwoPointDistance(dragPointF, stickyPointF);
if (mState == STATE_DRAG) {
if (isInsideRange()) {
stickRadius = (int) (defaultRadius - dragDistance / 10) < 10 ? 10 : (int) (defaultRadius - dragDistance / 10);
} else {
mState = STATE_MOVE;
if (onDragListener != null) {
onDragListener.onMove();
}
}
}
invalidate();
}
最后在QQBezierView 的onTouchEvent的UP事件中调用了setDragUp()方法:
public void setDragUp() {
if (mState == STATE_DRAG && isInsideRange()) {
//拖拽状态且在范围之内
startResetAnimator();
} else if (mState == STATE_MOVE) {
if (isInsideRange()) {
//在范围之内 需要RESET
startResetAnimator();
} else {
//在范围之外 消失动画
mState = STATE_DISMISS;
startExplodeAnim();
}
}
}
最后来看下DragView的onDraw方法,拖拽时的贝塞尔曲线以及拖拽滑动时的状态都是通过onDraw实现的:
@Override
protected void onDraw(Canvas canvas) {
if (isInsideRange() && mState == STATE_DRAG) {
mPaint.setColor(Color.RED);
//绘制固定的小圆
canvas.drawCircle(stickyPointF.x, stickyPointF.y, stickRadius, mPaint);
//首先获得两圆心之间的斜率
Float linK = MathUtil.getLineSlope(dragPointF, stickyPointF);
//然后通过两个圆心和半径、斜率来获得外切线的切点
PointF[] stickyPoints = MathUtil.getIntersectionPoints(stickyPointF, stickRadius, linK);
dragRadius = (int) Math.min(mWidth, mHeight) / 2;
PointF[] dragPoints = MathUtil.getIntersectionPoints(dragPointF, dragRadius, linK);
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);
canvas.drawPath(mPath, mPaint);
}
if (mCacheBitmap != null && mState != STATE_DISMISS) {
//绘制缓存的Bitmap
canvas.drawBitmap(mCacheBitmap, dragPointF.x - mWidth / 2,
dragPointF.y - mHeight / 2, mPaint);
}
if (mState == STATE_DISMISS && explodeIndex < explode_res.length) {
//绘制小红点消失时的爆炸动画
canvas.drawBitmap(bitmaps[explodeIndex], dragPointF.x - mWidth / 2, dragPointF.y - mHeight / 2, mPaint);
}
}
PS:最开始使用的是 Android:clipChildren=”false” 这个属性,如果父View只是一个普通的ViewGroup(如LinearLayout、RelativeLayout等),此时在父View中设置android:clipChildren=”false”后,子View就可以超出自己的范围,在ViewGroup中也可以滑动了,此时也没问题;但是当是RecycleView时,只要ItemView设置了background属性,滑动时的DragView就会显示在background的下面了,如有知其原因的还望不吝赐教~
最后再贴下源码下载地址:Android*QQ小红点
以上所述是小编给大家介绍的Android*QQ小红点功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# android 仿 qq 小红点
# 拖拽
# 小红点
# 塞尔
# 就可以
# 全屏
# 自定义
# 小圆
# 小编
# 范围之内
# 事件中
# 自己的
# 的是
# 都是
# 看着
# 就会
# 不吝赐教
# 也没
# 在此
# 下载地址
# 如有
相关文章:
如何快速搭建支持数据库操作的智能建站平台?
太原网站制作公司有哪些,网约车营运证查询官网?
如何制作算命网站,怎么注册算命网站?
黑客如何利用漏洞与弱口令入侵网站服务器?
威客平台建站流程解析:高效搭建教程与设计优化方案
学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?
如何快速搭建虚拟主机网站?新手必看指南
黑客如何通过漏洞一步步攻陷网站服务器?
制作ppt免费网站有哪些,有哪些比较好的ppt模板下载网站?
nginx修改上传文件大小限制的方法
浅谈Javascript中的Label语句
详解jQuery停止动画——stop()方法的使用
大连 网站制作,大连天途有线官网?
香港服务器建站指南:免备案优势与SEO优化技巧全解析
如何确认建站备案号应放置的具体位置?
网站制作培训多少钱一个月,网站优化seo培训课程有哪些?
c# Task.ConfigureAwait(true) 在什么场景下是必须的
定制建站是什么?如何实现个性化需求?
为什么Go需要go mod文件_Go go mod文件作用说明
佛山企业网站制作公司有哪些,沟通100网上服务官网?
广州网站设计制作一条龙,广州巨网网络科技有限公司是干什么的?
如何通过cPanel快速搭建网站?
简单实现Android验证码
设计网站制作公司有哪些,制作网页教程?
c# Task.Yield 的作用是什么 它和Task.Delay(1)有区别吗
再谈Python中的字符串与字符编码(推荐)
如何做网站制作流程,*游戏网站怎么搭建?
制作国外网站的软件,国外有哪些比较优质的网站推荐?
移民网站制作流程,怎么看加拿大移民官网?
建站之星图片链接生成指南:自助建站与智能设计教程
小米网站链接制作教程,请问miui新增网页链接调用服务有什么用啊?
大型企业网站制作流程,做网站需要注册公司吗?
免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?
网站设计制作公司地址,网站建设比较好的公司都有哪些?
如何使用Golang安装API文档生成工具_快速生成接口文档
电商网站制作公司有哪些,1688网是什么意思?
建站之星安装模板失败:服务器环境不兼容?
如何用花生壳三步快速搭建专属网站?
建站之星代理费用多少?最新价格详情介绍
深圳网站制作的公司有哪些,dido官方网站?
昆明高端网站制作公司,昆明公租房申请网上登录入口?
建站之星后台管理系统如何操作?
怎么制作网站设计模板图片,有电商商品详情页面的免费模板素材网站推荐吗?
,柠檬视频怎样兑换vip?
小说建站VPS选用指南:性能对比、配置优化与建站方案解析
网站制作需要会哪些技术,建立一个网站要花费多少?
西安大型网站制作公司,西安招聘网站最好的是哪个?
非常酷的网站设计制作软件,酷培ai教育官方网站?
油猴 教程,油猴搜脚本为什么会网页无法显示?
建站之星微信建站一键生成小程序+多端营销系统
*请认真填写需求信息,我们会在24小时内与您取得联系。