wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果
上一篇介绍了贝塞尔曲线的简单应用 仿360内存清理效果
这一篇带来一个 两条贝塞尔曲线的应用 : 仿qq未读消息去除效果。
转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50503630
老规矩,先上效果图:
qq的未读消息去除很炫酷,其实就是用了两条贝塞尔曲线,我们按思路来,先来画两个圆,及两条贝塞尔曲线,辅助点为圆心y坐标的一半。我们把下面移动的圆,叫做mMoveCircle.
这样一画,就很简单明了了对不对。只要在拖动的时候 去改变辅助点的Y,和固定圆的半径, 就可以出来如效果图的效果。
那么重写onTouchEvent
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
mMoveCircleY = event.getY(); // mSupY = mCircleY;
if (mMoveCircleY < lastY) {
isUp = false;
} else {
isUp = true;
}
lastY = mMoveCircleY;
invalidate();
break; case MotionEvent.ACTION_UP:
if((mMoveCircleY-mCircleY)>mMoveCircleRadius*3){ Log.e("wing","超过");
isCanDraw = false;
invalidate(); }else { Log.e("wing","没超过");
}
} return true;
}
这里Action_move记录了最后一次移动和这次移动的值,来代表是往上滑还是往下滑,改变一个标记为,并且让mMoveCircleY改变为触摸的y坐标。
ACTION_UP主要记录 圆点离开的范围,如果超过这个范围,则代表消息提醒去除掉。
在ondraw里绘制贝塞尔曲线
//左边的线
path.moveTo(mCircleX - mCircleRadius + mPaintStrokeWidth / 2, mCircleY);
path.quadTo(mCircleX , mSupY, mCircleX - mMoveCircleRadius + mPaintStrokeWidth / 2, mMoveCircleY);
canvas.drawPath(path, p); //右边的线
path.moveTo(mCircleX + mCircleRadius - mPaintStrokeWidth / 2, mCircleY);
path.quadTo(mCircleX, mSupY, mCircleX + mMoveCircleRadius - mPaintStrokeWidth / 2, mMoveCircleY);
canvas.drawPath(path, p);
这样可以画成两条贝塞尔曲线,但是是空心的
那么我们想象办法,如何才能让他封闭呢。还记得绘制多边形的办法吗。。直接在两条贝塞尔曲线之间lineto就可以了,然后close;
path.moveTo(mCircleX - mCircleRadius + mPaintStrokeWidth / 2, mCircleY);
path.quadTo(mCircleX , mSupY, mCircleX - mMoveCircleRadius + mPaintStrokeWidth / 2, mMoveCircleY);
path.lineTo(mCircleX + mMoveCircleRadius, mMoveCircleY);
path.quadTo(mCircleX, mSupY, mCircleX + mCircleRadius, mCircleY);
path.lineTo(mCircleX - mCircleRadius, mCircleY);
path.close();
canvas.drawPath(path, p);
其实我们绘制的是这个效果,然后在把两个实心圆画上去,画笔style设置为fill 即可、
封闭画笔,动态改变半径,绘制圆。
p.setStyle(Paint.Style.FILL);
if (isUp) {
canvas.drawCircle(mCircleX, mCircleY, mCircleRadius--, p);
canvas.drawCircle(mCircleX, mMoveCircleY, mMoveCircleRadius, p);
} else {
canvas.drawCircle(mCircleX, mCircleY, mCircleRadius++, p);
canvas.drawCircle(mCircleX, mMoveCircleY, mMoveCircleRadius, p);
}
得到如下效果。
最后,来判断是否超过一定下拉区域,如果超过 则圆点跟着手一起走 然后在手松开的时候消失。
if ((mMoveCircleY-mCircleY)<mMoveCircleRadius*3) {
Log.e("wing",mSupY-mCircleY+"");
Path path = new Path();
//左边的线
path.moveTo(mCircleX - mCircleRadius + mPaintStrokeWidth / 2, mCircleY);
path.quadTo(mCircleX , mSupY, mCircleX - mMoveCircleRadius + mPaintStrokeWidth / 2, mMoveCircleY);
path.lineTo(mCircleX + mMoveCircleRadius, mMoveCircleY);
path.quadTo(mCircleX, mSupY, mCircleX + mCircleRadius, mCircleY);
path.lineTo(mCircleX - mCircleRadius, mCircleY);
path.close();
canvas.drawPath(path, p);
//右边的线
// path.moveTo(mCircleX + mCircleRadius - mPaintStrokeWidth / 2, mCircleY);
// path.quadTo(mCircleX, mSupY, mCircleX + mMoveCircleRadius - mPaintStrokeWidth / 2, mMoveCircleY);
// canvas.drawPath(path, p);
p.setStyle(Paint.Style.FILL);
// canvas.drawCircle(mCircleX, mCircleY, mCircleRadius, p);
if (isUp) {
canvas.drawCircle(mCircleX, mCircleY, mCircleRadius--, p);
canvas.drawCircle(mCircleX, mMoveCircleY, mMoveCircleRadius, p);
} else {
canvas.drawCircle(mCircleX, mCircleY, mCircleRadius++, p);
canvas.drawCircle(mCircleX, mMoveCircleY, mMoveCircleRadius, p);
}
// canvas.drawPoint(mSupX, mSupY, p);
} else {
p.setStyle(Paint.Style.FILL);
canvas.drawCircle(mCircleX, mMoveCircleY, mMoveCircleRadius, p);
// canvas.drawCircle(mCircleX, mMoveCircleY, mMoveCircleRadius, p);
}
最后遗留一个复杂的问题, 用户可以360度拖动,这时候要根据圆 来计算切点的坐标,再来重新计算辅助点的坐标。比较繁琐,这里就不算了。 #其实我是不会#本篇的目的,了解贝塞尔曲线的应用我想已经达到了,读者若感兴趣,可以自行实现。#其实我是不会#
------------------------------------------------------------------------------解决篇-----------------------------------------------------------------------------------------------------
回到家又研究了一下360度动态转变的,终于想通怎么算了。如下图(无视那么丑 还有想吐槽下中性笔的油):
其实我们要面临的问题就是计算出 圆的切点坐标。 换言之就是求 ∠1 的角度。
由图可知 ∠1 = ∠2 ∠2 = ∠3 由于等价代换可得 ∠3 = ∠1
由图得:tan∠3 = (mCirlceY - mMoveCircleY)/(mMoveCircleX-mCircleX) 即∠1 = arctan (mCirlceY - mMoveCircleY)/(mMoveCircleX-mCircleX
则可计算右上点的坐标为:
x: mMoveCircleX - mMoveCircleRadius * sin∠1
y: mMoveCircleY - mMoveCircleRadius * cos∠1
其他三个切线点的坐标计算方法如上。得到四个点的坐标,只需要改变path的起终点 和 辅助点的坐标即可。由于过于繁杂,就不用代码给各位实现了。大家如果感兴趣,可以自行实现。#其实就是懒#
下一篇:wing带你玩转自定义view系列(3)模仿微信下拉眼睛
本项目地址:点击打开链接 求关注 求评论 求star
wing带你玩转自定义view系列(2) 简单模仿qq未读消息去除效果的更多相关文章
- wing带你玩转自定义view系列(1) 仿360内存清理效果
本篇是接自 手把手带你做自定义view系列 宗旨都是一样,带大家一起来研究自定义view的实现,与其不同的是本系列省去了简单的坐标之类的讲解,重点在实现思路,用简洁明了的文章,来与大家一同一步步学习. ...
- wing带你玩转自定义view系列(3)模仿微信下拉眼睛
发现了爱神的自定义view系列,我只想说一个字:凸(艹皿艹 ) !!相见恨晚啊,早看到就不会走这么多弯路了 另外相比之下我这完全是小儿科..所以不说了,这篇是本系列完结篇....我要从零开始跟随爱哥脚 ...
- 自定义View系列教程05--示例分析
站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定 ...
- 自定义View系列教程04--Draw源码分析及其实践
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- 自定义View系列教程01--常用工具介绍
站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Android多分辨率适配框架(3)- 使用指南 自定 ...
- 自定义View系列教程08--滑动冲突的产生及其处理
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- 自定义View系列教程07--详解ViewGroup分发Touch事件
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- 自定义View系列教程06--详解View的Touch事件处理
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
- 自定义View系列教程03--onLayout源码详尽分析
深入探讨Android异步精髓Handler 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)- 核心基础 Android多分辨率适配框架(2)- 原理剖析 Andr ...
随机推荐
- Java内存泄漏分析系列之二:jstack生成的Thread Dump日志结构解析
原文地址:http://www.javatang.com 一个典型的thread dump文件主要由一下几个部分组成: 上图将JVM上的线程堆栈信息和线程信息做了详细的拆解. 第一部分:Full th ...
- NLP系列(5)_从朴素贝叶斯到N-gram语言模型
作者: 龙心尘 && 寒小阳 时间:2016年2月. 出处: http://blog.csdn.net/longxinchen_ml/article/details/50646528 ...
- 自定义一个仿Spinner
两个布局文件: adpter_list.xml <?xml version="1.0" encoding="utf-8"?> <LinearL ...
- Leetcode难度表及解题汇总
Leetcode难度表及解题汇总 参考网上一份题目难度表,以及本人的解题. Id Question Difficulty Frequency Data Structures Algorithms Bl ...
- Android二维码扫描、生成
Android二维码扫描.生成 现在使用二维码作为信息的载体已经越来越普及,那么二维码的生成以及扫描是如何实现的呢 google为我们提供了zxing开源库供我们使用 zxing GitHub源码地址 ...
- Scala:提取器(Extractor)
http://blog.csdn.net/pipisorry/article/details/52902671 提取器是从传递给它的对象中提取出构造该对象的参数. Scala 标准库包含了一些预定义的 ...
- PHP Ajax JavaScript Json 实现天气信息获取
使用第三方服务 间接方式 思路 使用到的服务 实现代码 前端完整代码 总结 要在自己的网站上添加一个天气预报功能,是一个很普通的需求,实现起来也不是很难.今天来介绍几个简单的方法. 使用第三方服务 有 ...
- gloox配置聊天室
gloox配置聊天室 (金庆的专栏) gloox是XMPP协议的C++客户端库.以下代码测试创建多人聊天室(MUC), 并进行配置.参照gloox中的muc示例代码.gloox代码示例中没有聊天室的配 ...
- protobuf中的枚举缺省值应该为UNKNOWN
protobuf中的枚举缺省值应该为UNKNOWN(金庆的专栏)proto3中的枚举值为了与proto2兼容,要求缺省值固定为第1个,值为0.proto2中并没有规定对范围之外的枚举值的处理,而pro ...
- 给定一个实数数组,按序排列(从小到大),从数组从找出若干个数,使得这若干个数的和与M最为接近,描述一个算法,并给出算法的复杂度。
有N个正实数(注意是实数,大小升序排列) x1 , x2 ... xN,另有一个实数M. 需要选出若干个x,使这几个x的和与 M 最接近. 请描述实现算法,并指出算法复杂度. #define M 8 ...