学习目的
- 了解几何图形工具的用法
- 掌握画不规则图形的方法
应用场景:未读提醒,效果图:
效果图 | 效果图 | 效果图 |
---|---|---|
绘制一帧的效果
画一帧粘性控件的步骤分析
- 画一个固定圆
- 画一个拖拽圆
- 画中间连接部分
将中间连接部分水平放置,四个角的坐标定为固定值,分别标记上点的编号,矩形中心的点为控件点,画曲线时用
自定义一个GooView 继承View
|
|
第20-30 行用Path 画中间曲线部分
第25 行quadTo(x1,y1,x2,y2)方法可以画当前所在点到x2,y2 间的一条曲线,x1,y1 是当前点与x2,y2 间的一个控件点,它的位置决定曲线弯曲的方向和弧度,将GooView 显示到MainActivity 中
|
|
贝塞尔曲线
上述代码调用path.quadTo()画曲线,这种曲线叫贝塞尔曲线,有一个起点和终点,还可以有2个或3个控制点,其中控制点是控制曲线的弯曲形状,控制点不同,曲线的弯曲形状就不同。
替换变量
分别给拖拽圆,固定圆的圆心,半径,两个附着点命名,修改GooView 的onDraw()方法
|
|
第3-14 行替换附着点及控制点
第30-40 行替换拖拽圆及固定圆的圆心及半径 将替换后的变量转换成GooView 的成员变量
|
|
计算变量
拖拽圆和固定圆的圆心和半径已知,角3 的正弦值为两圆心纵坐标之差比上横坐标之差,则角3 的角度可知,则角1 可知,AB,AC 的长度即可计算出来,mDragPoints[0]的坐标可以计算出来,同理其它三个附着点坐标也可知。mControlPoint 为两圆心连线的中点
几何图形工具
|
|
利用几何图形工具类计算四个附着点坐标及控件点坐标
|
|
第3-17 行计算四个附着点及控制点坐标
计算固定圆半径
GooView 重写onSizeChanged()方法,计算状态栏高度
|
|
Utils.java
|
|
修改onDraw()方法
|
|
第18-20 行把画布向上移动状态栏的高度,移动前需要保存一下当前状态,做完操作后需要恢复一下状态,由于在onTouchEvent()中用的是getRawX(),getRawY()获取的是相对屏幕的坐标,所以GooView画图操作时需要向上移到一个状态栏的高度才能刚好和手指重合拖拽圆跟随手指移动时,随着拖拽与固定圆的距离的变大,固定圆的半径越来越小
|
|
第2 行定义最大的拖拽距离为80f
第7-24 行拖拽圆与固定圆的距离大于80f 时,取80f,通过两圆圆心的距离与80f 相对可以求出一个0.0f 到1.0f 的值,再通过估值器可以获得固定圆的半径在mStickRadius,mStickRadius*0.25f 间的变化值
第27-28 行通过两圆圆心的距离计算固定圆的半径tempStickRadius 第39,67 行将mStickRadius 替换成计算出来的半径tempStickRadius
事件处理
事件处理的分析
- 超出最大范围:拖拽圆与固定圆断开,松手后消失
- 超出最大范围:又放回去,恢复
- 没有超出最大范围:松手,回弹动画,恢复
事件处理的实现
修改onTouchEvent()方法
|
|
第1-2 行创建两个布尔变量记录是否已经消失及是否超出范围
第11-12 行手指重新按下时,重置变量 第21-27 行拖拽过程中记录是否超出范围
第32-38 行超出范围,松手,消失,标记当前为消失状态
第39-41 行超出范围,又放回去了,需要恢复,直接更新拖拽圆圆心为固定圆心即可
第45-62 行没有超出范围,松手,需要回弹动画,恢复 修改onDraw()方法
|
|
第31-54 行没有消失时,才绘制内容,没有超出范围时,才绘制连接部分及固定圆
事件的监听回调
定义监听接口
|
|
修改onTouchEvent()方法
|
|
第35-37 行标记消失时,回调onDisappear()方法
第41-42 行恢复时回调onReset()方法,此时超出过范围,所以参数传入true
第64-73 行添加动画监听,在动画结束时回调onReset()方法,此时没有超出范围,所以参数传入false
修改MainActivity 测试监听回调
|
|
RecyclerView的处理
如效果图看到的红色圆形控件为TextView并不是我们的GooView
item布局文件
|
|
圆形背景tv_showmsg_shape
|
|
处理RecyclerView
|
|
加入RecyclerView后的事件分发问题(事件分发机制)
加入GooView后的处理
实现效果的原理:当用户触摸到右侧的圆形背景TextView的时候,让TextView隐藏,利用WindowManager添加GooView当松开手后,将GooView移除,让TextView显示
GooView的准备工作
让GooView能够显示文本,定义为GooView设置文本的方法
|
|
在onDraw方法中绘制文本
添加为GooView初始化位置的方法
处理适配器为GooView设置触摸监听
|
|
触摸监听的实现:添加GooView并设置位置和文本
|
|
出现的bug1:触摸TextView然后向上移动,GooView不懂,RecyclerView动
事件被RecyclerView拦截了,需要请求RecyclerView不要拦截事件。事件分发涉及的基本概念:
- onTouchEvent:触摸事件的处理
- dispatchTouchEvent:传递触摸事件
- onInterceptTouchEvent:拦截事件传递
- requestDisallowedInterceptTouchEvent(boolean disallowIntercept):请求自己的父布局不要拦截事件
事件分发原理:解决触摸监听优于onTouchEvent获取事件的问题,处理:
|
|
出现的bug2:移动后抬起手,GooView不消失
原因:利用WindowManger添加的视图比较特殊,不能直接移除,需要用windowManager.removeView(view);来移除
但,作为OnShowGooViewTouchListener并不知道什么时候该移除GooView,故:使用接口回调来处理这个问题
在GooView中定义接口:
当消失的时候调用消失的回调方法:
在OnShowGooViewTouchListener中设置和实现监听,并实现两个回调方法