一个类似于QQ语音聊天时的拖拽移动悬浮小球
闲来无事,分享一个最近在某个地方借鉴的一个demo(原谅我真的忘了在哪里看到的了,不然也就贴地址了)这个demo的逻辑思路并不是很难,推敲一下,很快就能理解,只是觉得这样的一个组合控件用起来蛮能增色自己的APP的,所以也就记下了。
先给你们看一下效果图。
这里的悬浮小球其实是一个组合控件,可以在上面加上其他效果。之后我会上传demo。如果要做成QQ语音的那种,可以把图片移除,换上一个label,在label上加上时间久可以了,用的时候,可以直接把这个类拖进工程,直接加到想要添加的仕途上就可以啦。
这个demo我也是学习过程中做了很多注释,基本上都应该能看懂,还是一样不多解释,看注释看代码。^_^
这是还是说一下具体的实现功能吧:
第一个:是营造一个呼吸的效果,这个呼吸效果实际上只是一个假象,UI控件哪有什么呼吸的嘛,都是自己YY的。这个呼吸效果实际上是通过动画效果改变Alpha,不断循环,达到一致循环改变Alpha,感觉就像是在呼吸一样。
第二个:是图片效果,这里是采用了UIImageRenderingModeAlwaysTemplate,不懂得同学可以查一下,不过我demo里面也有部分解释。这里主要是忽略的图片的颜色,设置成自己想要的颜色(这里的图片原本是黑色的,我通过这个枚举,让他的颜色变成了白色)
第三个:是移动,这里是通过-(void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event , -(void)touchesMoved:(NSSet )touches withEvent:(UIEvent )event以及 – (void)touchesEnded:(NSSet )touches withEvent:(UIEvent )event 这三个方法来实现移动的,大致就是触摸时取出触摸点坐标,然后作为悬浮小球的center,实现了小球的移动。
//将触摸点赋值给touchView的中心点 也就是根据触摸的位置实时修改view的位置
self.center = [startTouch locationInView:self.superview];
还有一个注意的是在开始移动之前一定要把之前的效果给移除掉,不然会很奇葩的,不信你也可以试一试。
// 移除之前的所有行为
// 如果不移除,之前移动所触发的物理吸附事件就会一直执行
[self.animator removeAllBehaviors];
第四:就是计算计算距离最近的边缘 吸附到边缘停靠,具体的计算就不说了,因为太繁琐了,没有想着优化,看看啥时候闲下来再来看看能不能优化吧。主要就是考虑的情况稍微多了点,但是逻辑上还是很清晰的。这里有一个吸附的物理行为,其实也就是一个动画效果,直接加上就好了,也不是很复杂。
好的,具体的都解释完了。上代码!!!,突然发现并不能传文件,好吧,赋值过来看看吧
这是.h里面的代码
这里只是给外界留了个借口,这些属性也可以.m里面,我只是在外界用到了这个而已。
#import
typedef void (^DownLoadBlock) ();
@interface xuanfuwu : UIView
@property (nonatomic ,assign) CGPoint startPoint;//触摸起始点
@property (nonatomic ,assign) CGPoint endPoint;//触摸结束点
@property (nonatomic ,copy) DownLoadBlock downLoadBlock;
@end
这是.m里面的代码
//主题颜色
#import "AppDelegate.h"
#import "xuanfuwu.h"
#define MAINCOLOER [UIColor colorWithRed:105/255.0 green:149/255.0 blue:246/255.0 alpha:1]
#define kDownLoadWidth 60
#define kOffSet kDownLoadWidth / 2
@interface xuanfuwu ()
@property (nonatomic , retain ) UIView *backgroundView;//背景视图
@property (nonatomic , retain ) UIImageView *imageView;//图片视图
@property (nonatomic , retain ) UIDynamicAnimator *animator;//物理仿真动画
@end
@implementation xuanfuwu
//初始化
- (instancetype)initWithFrame:(CGRect)frame{
// 设置 xuanfuwu 这个视图的大小 宽高都是60
frame.size.width = kDownLoadWidth;
frame.size.height = kDownLoadWidth;
if (self = [super initWithFrame:frame]) {
//初始化背景视图
_backgroundView = [[UIView alloc]initWithFrame:CGRectMake(0, 0, CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))];
// 让初始化背景变成圆
_backgroundView.layer.cornerRadius = _backgroundView.frame.size.width / 2;
// clipsToBounds
// 是指视图上的子视图,如果超出父视图的部分就截取掉,
// masksToBounds
// 却是指视图的图层上的子图层,如果超出父图层的部分就截取掉
_backgroundView.clipsToBounds = YES;
// 设置颜色和透明度
_backgroundView.backgroundColor = [MAINCOLOER colorWithAlphaComponent:0.7];
_backgroundView.userInteractionEnabled = NO;
[self addSubview:_backgroundView];
//初始化图片背景视图
// 比背景视图稍微小一点,显示出呼吸的效果
UIView * imageBackgroundView = [[UIView alloc]initWithFrame:CGRectMake(5, 5, CGRectGetWidth(self.frame) - 10, CGRectGetHeight(self.frame) - 10)];
// 变圆
imageBackgroundView.layer.cornerRadius = imageBackgroundView.frame.size.width / 2;
imageBackgroundView.clipsToBounds = YES;
imageBackgroundView.backgroundColor = [MAINCOLOER colorWithAlphaComponent:0.8f];
imageBackgroundView.userInteractionEnabled = NO;
[self addSubview:imageBackgroundView];
//初始化图片
_imageView = [[UIImageView alloc]initWithImage:[[UIImage imageNamed:@"1.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
// UIImageRenderingModeAutomatic // 根据图片的使用环境和所处的绘图上下文自动调整渲染模式。
// UIImageRenderingModeAlwaysOriginal // 始终绘制图片原始状态,不使用Tint Color。
// UIImageRenderingModeAlwaysTemplate // 始终根据Tint Color绘制图片,忽略图片的颜色信息。
_imageView.tintColor = [UIColor whiteColor];
_imageView.frame = CGRectMake(0, 0, 30, 30);
_imageView.center = CGPointMake(kDownLoadWidth / 2 , kDownLoadWidth / 2);
[self addSubview:_imageView];
//将正方形的view变成圆形
self.layer.cornerRadius = kDownLoadWidth / 2;
//开启呼吸动画
[self HighlightAnimation];
}
return self;
}
// 触摸事件的触摸点
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//得到触摸点
UITouch *startTouch = [touches anyObject];
//返回触摸点坐标
self.startPoint = [startTouch locationInView:self.superview];
// 移除之前的所有行为
// 如果不移除,之前移动所触发的物理吸附事件就会一直执行
[self.animator removeAllBehaviors];
}
//触摸移动
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
//得到触摸点
// 这里只有一个手指,移动的坐标只有一个
UITouch *startTouch = [touches anyObject];
//将触摸点赋值给touchView的中心点 也就是根据触摸的位置实时修改view的位置
self.center = [startTouch locationInView:self.superview];
}
//结束触摸
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
//得到触摸结束点
UITouch *endTouch = [touches anyObject];
//返回触摸结束点
// 这个方法是指:触摸的点时在哪个视图,xuanfuwu 是加在viewController上的,所以用superView
self.endPoint = [endTouch locationInView:self.superview];
//判断是否移动了视图 (误差范围5)
CGFloat errorRange = 5;
if (( self.endPoint.x - self.startPoint.x >= -errorRange && self.endPoint.x - self.startPoint.x = -errorRange && self.endPoint.y - self.startPoint.y bottomRange ? bottomRange : topRange;//获取上下最小距离
CGFloat minRangeLR = leftRange > rightRange ? rightRange : leftRange;//获取左右最小距离
CGFloat minRange = minRangeTB > minRangeLR ? minRangeLR : minRangeTB;//获取最小距离
//判断最小距离属于上下左右哪个方向 并设置该方向边缘的point属性
CGPoint minPoint;
if (minRange == topRange) {
//上
endX = endX - kOffSet superwidth ? superwidth - kOffSet : endX;
minPoint = CGPointMake(endX , 0 + kOffSet);
} else if(minRange == bottomRange){
//下
endX = endX - kOffSet superwidth ? superwidth - kOffSet : endX;
minPoint = CGPointMake(endX , superheight - kOffSet);
} else if(minRange == leftRange){
//左
endY = endY - kOffSet superheight ? superheight - kOffSet : endY;
minPoint = CGPointMake(0 + kOffSet , endY);
} else if(minRange == rightRange){
//右
endY = endY - kOffSet superheight ? superheight - kOffSet : endY;
minPoint = CGPointMake(superwidth - kOffSet , endY);
}
//添加吸附物理行为
UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self attachedToAnchor:minPoint];
// 吸附行为中的两个吸附点之间的距离,通常用这个属性来调整吸附的长度,可以创建吸附行为之后调用。系统基于你创建吸附行为的方法来自动初始化这个长度
[attachmentBehavior setLength:0];
// 阻尼,相当于回弹过程中额阻力效果
[attachmentBehavior setDamping:0.1];
// 回弹的频率
[attachmentBehavior setFrequency:3];
[self.animator addBehavior:attachmentBehavior];
}
}
#pragma mark ---UIDynamicAnimatorDelegate
- (void)dynamicAnimatorDidPause:(UIDynamicAnimator *)animator{
}
#pragma mark ---LazyLoading
- (UIDynamicAnimator *)animator
{
if (!_animator) {
// 创建物理仿真器(ReferenceView : 仿真范围)
_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.superview];
//设置代理
_animator.delegate = self;
}
return _animator;
}
#pragma mark ---BreathingAnimation 呼吸动画
// 实质就是一个循环动画,透明度来回改变
- (void)HighlightAnimation{
// 修改block块里面的值
__block typeof(self) Self = self;
[UIView animateWithDuration:1.5f animations:^{
Self.backgroundView.backgroundColor = [Self.backgroundView.backgroundColor colorWithAlphaComponent:0.1f];
} completion:^(BOOL finished) {
[Self DarkAnimation];
}];
}
- (void)DarkAnimation{
__block typeof(self) Self = self;
[UIView animateWithDuration:1.5f animations:^{
Self.backgroundView.backgroundColor = [Self.backgroundView.backgroundColor colorWithAlphaComponent:0.6f];
} completion:^(BOOL finished) {
[Self HighlightAnimation];
}];
}
一个类似于QQ语音聊天时的拖拽移动悬浮小球的更多相关文章
- reactnative实现qq聊天消息气泡拖拽消失效果
前言(可跳过) 我在开发自己的APP时遇到了一个类似于qq聊天消息气泡拖拽消息的需求,因为在网上没有找到相关的组件,所以自己动手实现了一下 需求:对聊天消息气泡拖拽到一定长度松开时该气泡会消失(可自行 ...
- 一个可以自由定制外观、支持拖拽消除的MaterialDesign风格Android BadgeView
为了尊重作者,先放上链接:https://github.com/qstumn/BadgeView BadgeView 一个可以自由定制外观.支持拖拽消除的MaterialDesign风格Android ...
- Qt无边框窗体-最大化时支持拖拽还原
目录 一.概述 二.效果展示 三.demo制作 1.设计窗体 2.双击放大 四.拖拽 五.相关文章 原文链接:Markdown模板 一.概述 用Qt进行开发界面时,既想要实现友好的用户交互又想界面漂亮 ...
- 让一个view 或者控件不支持拖拽
让一个view 或者控件不支持拖拽: dragView.userInteractionEnabled = NO;
- java网络编程(三):一个类似QQ的聊天程序
客户端: package QQ; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import ...
- QQ中未读气泡拖拽消失的实现(参照一位年轻牛B的博主的思路自己实现了一下)
原文链接:http://kittenyang.com/drawablebubble/,博主年轻却很有思想.相仿的年纪,很佩服他! 首先分析拖拽时的图,大圆.不规则的图(实际上时有规律的不然也画不出来, ...
- EasyUI, Dialog 在框架页(ifrmae)的Top页面弹出时,拖拽Dialog边缘(以改变窗口大小),UI界面被卡死的解决办法
将Dialog的modal属性设置为true,可以解决卡死的问题(但会给用户使用体验带来影响) var par = { title: This.title, width: This.width, he ...
- 拖拽一个元素如此简单,mouse、drag、touch三兄弟的用处
最近需要做一个投票活动,上传图片时需要拖拽.缩放来裁剪图片,vue的组件不少,不过自己动手才能丰衣足食,一味使用别人的组件实在难以进步,所以自己研究一番. 一.mouse.drag.touch傻傻分不 ...
- 使用Servlet和JSP实现一个简单的Web聊天室系统
1 问题描述 利用Java EE相关技术实现一个简单的Web聊天室系统,具体要求如下. (1)编写一个登录 ...
随机推荐
- Android之单复选框及Spinner实现二级联动
一.基础学习 1.图形学真的很神奇啊....查了些资料做出了3D云标签,哈哈...其实直接拿来用的,我们要效仿鲁迅先生的拿来主义,嘿嘿~~3D标签云就是做一个球面,然后再球面上取均匀分布的点,把点坐标 ...
- 二维卷积c代码
二维卷积c代码 二维信号的卷积原理请参考另外一篇文章:http://blog.csdn.net/carson2005/article/details/43702241 这里直接给出参考代码: void ...
- 【2011 Greater New York Regional 】Problem B The Rascal Triangle
一个简单的规律题,每一列都是一个等差数列: 代码: #include<cstdio> #define ll long long using namespace std; int main( ...
- Android 网络请求详解
我们知道大多数的 Android 应用程序都是通过和服务器进行交互来获取数据的.如果使用 HTTP 协议来发送和接收网络数据,就免不了使用 HttpURLConnection 和 HttpClient ...
- 监控持有sql和被堵塞的sql
Session 1: mysql> start transaction; Query OK, 0 rows affected (0.00 sec) mysql> update Client ...
- op论坛,分支
http://www.arm9home.net/thread.php?fid=68 http://www.openwrt.org.cn/bbs/forum.php https://dev.openwr ...
- C 语言字符串(译)
C 语言的 switch 语句非常强大.然而,它不能用字符串作为判断条件,只能用常整数.这是可以理解的,因为 C 的字符串仅仅是数组,它们并不是并不是一个整体. 在某些情况下,将 string 作为 ...
- bzoj1202
很久以前写的,忘补解题报告了首先似乎dfs就可以了吧?但还有更高大上的做法其实这东西就是告诉sum[y]-sum[x-1]=z然后给出一堆看成不成立可以用并查集,维护每个点到father点的差即可 . ...
- ☀【组件】getRequest
→ GitHub <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset=&qu ...
- 备份及还原Xcode的模拟器
http://blog.csdn.net/it_magician/article/details/8749876 每次更新或者重装Xcode之后,最麻烦的莫过于各个模拟器的安装了,因为下载速度实在让人 ...