- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章IOS设置QQ小红点消除的方法(一键退朝)由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
qq上黏黏的小红点很好玩有木有,于是自己也想实现一番,看到ios实现的人比较少,android的比较多,于是这个就用ios来实现哈~ 。
效果图:
调试图:
其实从实现来讲,我是先实现第二张图的效果的.
我小编给大家说下实现思路 。
1.了解原理,以及如何绘制“黏黏”形状(即绘制两圆加两条贝塞尔曲线).
2.新建uiview(azmetaballcanvas),作为单独画布用来绘制“黏黏”形状,用程序实现算法,并绘制出来.
3.给画布(azmetaballcanvas)添加attach:(uiview *)方法,并添加手势监听,重绘,使得任意 view 都能够被在画布上拥有“黏黏”效果.
4.根据连心线的距离加上判断是否要断开,用户手指离开时也要根据距离来判断是爆炸动画还是回弹动画.
详细过程 。
首先必须要了解小红点拖拽的过程形状是什么,其实就是类似元球效果(metaball)。仔细观察可分析发现,就是两个大小不一样的圆加上两条贝塞尔曲线构成的.
关于算法部分,我已经分解成了另外一篇博文,强烈建议不清楚该形状是怎么画出来的同学先看一下《【算法分析】qq“一键退朝”之详细计算方法》 。
1.绘制拖拽 。
既然怎么求坐标点画出来我们已经知道了,现在就可以去实现了.
首先新建一个“画布”,继承自uiview 。
1
2
3
4
5
|
//azmetaballcanvas.h
@interface azmetaballcanvas : uiview
@property(nonatomic,strong) circle *centercircle;
@property(nonatomic,strong) circle *touchcircle;
@end
|
circle为自定义实体类,里面定义了一些圆的基本属性,如圆心坐标、半径等.
为什么要新建一个画布?
因为小红点是能够全屏拖动的,别看qq上它存在某一行cell,但其实你可以把它拉到别的cell上去,这就需要给小红点足够的位置来绘制,就干脆新建一个画布专门用来绘制小红点的动作好了.
azmetaballcanvas目前包含两个属性,两个圆,一个中心圆,一个触摸圆,按照需求来看,中心圆应该是位置不变的,触摸圆会跟随手指触摸屏幕的位置而改变,后面需要在两个圆之间画上贝塞尔曲线来构成元球效果.
接下来开始写azmetaballcanvas的实现 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//azmetaballcanvas.m
#define radius 40.0
@interface azmetaballcanvas() {
uibezierpath *_path;
cgpoint _touchpoint;
}
@end
@implementation azmetaballcanvas
- (instancetype)initwithcoder:(nscoder *)adecoder {
self = [super initwithcoder:adecoder];
nslog(@
"initwithcorder"
);
if
(self) {
[self initdata];
}
return
self;
}
- (
void
)initdata {
_touchcircle = [circle initwithcenterpoint:self.center radius:radius];
_centercircle = [circle initwithcenterpoint:self.center radius:radius];
_touchpoint = self.center;
nslog(@
"self.center (%f, %f)"
, self.center.x, self.center.y);
}
@end
|
先初始化两个圆的位置,默认在view的中心,并在init、initwithframe、initwithcoder等父类构造函数中加入自定义初始化方法initdata.
重写绘制方法 。
如同android中的ondraw(),ios中的drawrect能够被重写绘制,然后调用[view setneedsdisplay]来通知重绘.
1
2
3
4
5
6
7
8
9
|
- (
void
)drawrect:(cgrect)rect {
_path = [[uibezierpath alloc] init];
[self drawcentercircle];
[self drawtouchcircle:_touchpoint];
[self drawbeziercurvewithcircle1:_centercircle circle2:_touchcircle];
}
|
如同算法分析中所讲,在绘制的时候,我们只需要绘制两个圆(drawcentercircle、drawtouchcircle)和连接两圆的贝塞尔曲线(drawbeziercurve),算法其实就是照抄《【算法分析】qq“一键退朝”之详细计算方法》 。
ios自带贝塞尔曲线uibezierpath,其自带画圆方法addarcwithcenter: radius: startangle: endangle: clockwise:,所以我们只要调用就好啦! 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
#pragma mark draw circle --- 画圆
- (
void
) drawcentercircle {
[self drawcircle:_path circle:_centercircle];
}
- (
void
) drawtouchcircle:(cgpoint)center {
_touchcircle.centerpoint = center;
[self drawcircle:_path circle:_touchcircle];
}
- (
void
)drawcircle:(uibezierpath *)path circle:(circle *)circle {
[_path addarcwithcenter:circle.centerpoint radius:circle.radius startangle:0 endangle:360 clockwise:
true
];
[_path fill];
[_path stroke];
[_path removeallpoints];
}
#pragma mark draw curve --- 画贝塞尔曲线
- (
void
)drawbeziercurvewithcircle1:(circle *)circle1 circle2:(circle *)circle2 {
float
circle1_x = circle1.centerpoint.x;
float
circle1_y = circle1.centerpoint.y;
float
circle2_x = circle2.centerpoint.x;
float
circle2_y = circle2.centerpoint.y;
//连心线的长度
float
d =
sqrt
(powf(circle1_x - circle2_x, 2) + powf(circle1_y - circle2_y, 2));
//连心线x轴的夹角
float
angle1 =
atan
((circle2_y - circle1_y) / (circle1_x - circle2_x));
//连心线和公切线的夹角
float
angle2 =
asin
((circle1.radius - circle2.radius) / d);
//切点到圆心和x轴的夹角
float
angle3 = m_pi_2 - angle1 - angle2;
float
angle4 = m_pi_2 - angle1 + angle2;
float
offset1_x =
cos
(angle3) * circle1.radius;
float
offset1_y =
sin
(angle3) * circle1.radius;
float
offset2_x =
cos
(angle3) * circle2.radius;
float
offset2_y =
sin
(angle3) * circle2.radius;
float
offset3_x =
cos
(angle4) * circle1.radius;
float
offset3_y =
sin
(angle4) * circle1.radius;
float
offset4_x =
cos
(angle4) * circle2.radius;
float
offset4_y =
sin
(angle4) * circle2.radius;
float
p1_x = circle1_x - offset1_x;
float
p1_y = circle1_y - offset1_y;
float
p2_x = circle2_x - offset2_x;
float
p2_y = circle2_y - offset2_y;
float
p3_x = circle1_x + offset3_x;
float
p3_y = circle1_y + offset3_y;
float
p4_x = circle2_x + offset4_x;
float
p4_y = circle2_y + offset4_y;
cgpoint p1 = cgpointmake(p1_x, p1_y);
cgpoint p2 = cgpointmake(p2_x, p2_y);
cgpoint p3 = cgpointmake(p3_x, p3_y);
cgpoint p4 = cgpointmake(p4_x, p4_y);
cgpoint p1_center_p4 = cgpointmake((p1_x + p4_x) / 2, (p1_y + p4_y) / 2);
cgpoint p2_center_p3 = cgpointmake((p2_x + p3_x) / 2, (p2_y + p3_y) / 2);
[self drawbeziercurvestartat:p1 endat:p2 controlpoint:p2_center_p3];
[self drawlinestartat:p2 endat:p4];
[self drawbeziercurvestartat:p4 endat:p3 controlpoint:p1_center_p4];
[self drawlinestartat:p3 endat:p1];
[_path movetopoint:p1];
[_path closepath];
[_path stroke];
}
|
2.监听手势 。
简单版 。
最简单的其实就是直接在azmetaballcanvas中重写touchxxx等一系列方法,然后在其中调用setneedsdisplay通知uiview重绘.
1
2
3
4
5
6
7
8
9
10
11
|
#pragma mark touch event
- (
void
)touchesbegan:(nsset<uitouch *> *)touches withevent:(uievent *)event {
uitouch *touch = [touches anyobject];
_touchpoint = [touch locationinview:self];
[self setneedsdisplay];
}
- (
void
)touchesmoved:(nsset<uitouch *> *)touches withevent:(uievent *)event {
uitouch *touch = [touches anyobject];
_touchpoint = [touch locationinview:self];
[self setneedsdisplay];
}
|
现在其实差不多第二张图的效果已经出来了,差的就是更改两圆的半径方法.
改变半径的方法就非常简单了 。
1
2
3
4
5
6
7
8
9
|
#pragma 改变半径
-(
void
)changecentercircleradiusto:(
float
)radius {
_centercircle.radius = radius;
[self setneedsdisplay];
}
-(
void
)changetouchcircleradiusto:(
float
)radius {
_touchcircle.radius = radius;
[self setneedsdisplay];
}
|
普通版 。
根据现象发现,我们需要通过拖拽小红点来移动它,而不是我们手指点哪,小红点就在哪,所以我们需要给小红点增加手势监听,而不是“画布”.
于是我们改为在画布添加方法- (void)attach:(uiview *)item;,然后再给传入的view添加pan手势.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
- (
void
)attach:(uiview *)item {
uipangesturerecognizer *drag = [[uipangesturerecognizer alloc] initwithtarget:self action:@selector(drag:)];
item.userinteractionenabled = yes;
[item addgesturerecognizer:drag];
}
- (
void
)drag:(uipangesturerecognizer *)recognizer {
//得到触摸点
_touchpoint = [recognizer locationinview:self];
//得到触摸的view
uiview *touchview = recognizer.view;
switch
(recognizer.state) {
case
uigesturerecognizerstatebegan:{
//touch开始:在画布上绘制一个touchview的副本
//...此部分参看源码
break
;
}
case
uigesturerecognizerstatechanged:{
//移动中:记录触摸位置,更改touchview和touchcircle的坐标位置
[self resettouchcenter:_touchpoint];
break
;
}
case
uigesturerecognizerstateended: {
//touch结束:根据连心线长度判断是执行爆炸动画还是弹簧动画
//...此部分参看源码
break
;
}
default
:
break
;
}
[self setneedsdisplay];
//重绘
}
|
以上内容是小编给大家介绍的ios设置qq小红点消除的方法(一键退朝),希望对大家有所帮助.
最后此篇关于IOS设置QQ小红点消除的方法(一键退朝)的文章就讲到这里了,如果你想了解更多关于IOS设置QQ小红点消除的方法(一键退朝)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
这个问题在这里已经有了答案: What does the construct x = x || y mean? (12 个答案) 关闭 8 年前。 我已经下载了一个 javascript 脚本,第一
此前苹果下架QQ HD iPadOS 版,因此无法登陆QQ HD账号,这也给不少用户们造成了困扰。那么QQ HD平板版为什么下架无法使用呢?此外QQ HD版本用不了要如何解决呢?下面一起来看看吧!
我正要对两个 select 语句执行 join。 select x.A from (select blah - Q1 )x join (select blah - Q2 ) y on x.A = y.
最近做一个邮箱验证的功能,研究了一会,搞定了邮件的自动发送。下面用qq邮箱作为演示,一步一步来解释: 代码下载地址 首先,就是做到邮件的发送,代码如下: ?
常用的正则匹配表达式 正则表达式--验证手机号码:13[0-9]{9} 实现手机号前带86或是+86的情况:^((\+86)|(86))?(13)\d{9}$ 电话号码与手机号码同时验证:(^(\
能够查看您的数据很有帮助。当您有多个变量时,您可以形成一个散点图矩阵,例如,pairs()。散点图矩阵为您提供一组数据的二维边缘投影。 set.seed(8092) X <- matrix(rnorm
我有两个目录,每个目录都有一个文件: $ ls -l "test dir[" -rw-r--r-- 1 root media 0B 11 Dec 16:53 .ignoreme 和 $ l
我正在我的 MVC 3 应用程序中开发文件上传功能。我让它正常工作(有点),问题出在 onComplete 函数中,当我尝试删除 qq-uploader 类时,它会从所有选中的表格单元格中删除。工作流
我需要为网站的中文翻译实现相当于推文按钮,即不是我已经得到的“在微博上分享”按钮(使用生成器 here ) , 而是一个腾讯/QQ 微博分享按钮。 到目前为止我做了什么: 订阅了微博(阅读自动谷歌翻译
我是新手,通常来自 R。我想创建一个包含多条线的 QQ-Plot。 我有一个 beta 分布式数据集我想为 beta 分布尝试不同的参数,并在 one QQ-Plot 中比较它们以获得更好的比较。如果
本文实例为大家分享了php微信分享到朋友圈、QQ、朋友、微博的具体代码,供大家参考,具体内容如下 前台代码 <script src="http://res.wx.qq.com
我一直在尝试用 python 绘制泊松分布的 QQ 图。这是我到目前为止所拥有的: import numpy as np import statsmodels.api as sm import sci
我正在使用插件qq.FileUploader . 在提交文件之前,我想知道是否已经上传过同名文件。 我正在使用此代码: var uploader = new qq.FileUploader({
这个问题在这里已经有了答案: Convert Pandas Column to DateTime (8 个答案) 关闭 4 年前。 我有一个 pandas 数据框,其中有一列应该指示财政季度结束。格
本文实例讲述了php版微信支付api.mch.weixin.qq.com域名解析慢原因与解决方法。分享给大家供大家参考,具体如下: 微信支付api.mch.weixin.qq.com域名解析慢了,
我怎样才能像这样插值: {-# LANGUAGE QuasiQuotes #-} import Text.RawString.QQ myText :: Text -> Text myText myVa
对不起,如果这在某处记录,但我一直无法找到它。将括号定界符与 qq 一起使用时, 代码未插值: qq.raku #!/usr/bin/env raku say qq{"Two plus two": {
我生成了一个 QQ 图来将我的随机数生成器的分布与 beta 分布进行比较。我可以通过 使用 R 中常用的绘图命令来完成此操作 samples1 <- read.csv("test1-clean.da
所以我得到了一个使用 AJAX 动态加载的对话框,在那个框中,我有一个文件输入被 Valums qq.FileUploader 替换。加载内容后,我确实在 FileUploader 上调用了 init
我有一个原始样本数据和它的模拟数据(不要问我是怎么模拟的),我想检查直方图是否匹配。所以最好的方法是通过 qqplot 但是 statsmodels 库不允许不同大小的样本。 最佳答案 构建 qq 图
我是一名优秀的程序员,十分优秀!