当前位置: 首页 > 编程日记 > 正文

【UIDynamic例子】挂起的方块

通过前面的动力学小Demo(本文默认你已经看过这篇Blog:传送门),我们对UIKit中的UIDynamic已经有了初步的认识。现在我们写个更加有趣的Demo:模拟一个用弹性绳子挂起的小方块,用户可以将它拖动到屏幕任意位置,松手后小方块将在重力和绳子弹力的作用下进行运动,而运动过程完全由UIDynamic控制!



开始吧

新建项目,在ViewController中添加全局变量:

@interface ViewController (){UIDynamicAnimator* _animator;UIGravityBehavior* _gravity;UIAttachmentBehavior *_attach;UIView *_plateView;
}

上面代码分别声明 动力学引擎、重力行为模型、连接行为模型、小方块的变量。


然后在viewDidLoad中进行初始化:

_plateView = [[UIView alloc] initWithFrame:CGRectMake(80, 150, 60, 60)];
_plateView.backgroundColor = [UIColor orangeColor];
[self.view addSubview:_plateView];_animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];_gravity = [[UIGravityBehavior alloc] initWithItems:@[_plateView]];
[_animator addBehavior:_gravity];<p style="margin-top: 0px; margin-bottom: 0px; line-height: normal; font-family: Helvetica; color: rgb(69, 69, 69);">_attach = [[UIAttachmentBehavior alloc] initWithItem:_plateView attachedToAnchor:CGPointMake(200, 100)];</p>_attach.length = 60.0;
_attach.damping = 0.1;
_attach.frequency = 0.6;
[_animator addBehavior:_attach];

上面的代码做了下面的事情:

1.在屏幕上添加了一个橘色的小方块。

2.创建并初始化动力学引擎,设置self.view作为参考系

3.创建并初始化重力行为模型,并与小方块关联,添加到动力学引擎中。

4.创建并初始化连接行为模型(下文统称为绳子吧),初始化时除了与小方块关联,还设置了锚点为(200,100)。另外还设置绳子的相关属性(长度、弹性、频率),最后添加到动力学引擎中。

运行项目:




已经可以看到方块在受到重力、绳子拉力的作用下,运动啦!不过还看不到绳子,这个需要我们自己画啦。另外,拖动小方块,什么事情都没发生。。。



添加绳子

现在我们自己来绘制绳子吧。体育老师说过两点确定一根直线,因此我们需要找到两个关键点,也就是锚点(也就是绳子顶端,我们就称作A点吧),以及绳子与方块的连接点(我们姑且称为B点)。点A已经由我们确定了是(200,100),点B我们取方块上边缘的中间,坐标是....? 


好像这个坐标并不是固定的,在方块运动过程中,B也随着时间变动着。因此我们需要监听方块的运动,得到每一时刻B点的新坐标,将AB连点进行连接画线。怎样得到B点的最新坐标呢?我们可以通过KVO,监听方块center属性改变的事件,既在viewDidLoad最后添加:

[_plateView addObserver:self forKeyPath:@"center" options:NSKeyValueObservingOptionNew context:nil];

并实现回调方法:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{[self updateLine];
}

添加上面的方法后,只要方块运动,都会回调上面的方法,我们在方法里调用updateLine方法更新绳子,updateLine方法利用CAShapeLayer和贝塞尔曲线绘制绳子。

先声明一个CAShapeLayer类型的全局变量:

CAShapeLayer *_lineLayer;

完成 updateLine方法,进行绳子的绘制:

-(void)updateLine{if (nil == _lineLayer) {_lineLayer = [CAShapeLayer layer];_lineLayer.strokeColor = [UIColor purpleColor].CGColor;_lineLayer.fillColor = [UIColor clearColor].CGColor;_lineLayer.lineWidth = 1.5f;_lineLayer.lineJoin = kCALineJoinRound;_lineLayer.strokeEnd = 1.0f;[self.view.layer addSublayer:_lineLayer];}CGPoint platePoint = [self.view convertPoint:CGPointMake(CGRectGetMidX(_plateView.bounds), 0) fromView:_plateView];UIBezierPath *bezierPath = [UIBezierPath bezierPath];[bezierPath moveToPoint:_attach.anchorPoint];[bezierPath addLineToPoint:platePoint];_lineLayer.path = bezierPath.CGPath;
}

在上面的代码中,platePoint即是我们需要的B点,这里使用了系统函数covertPoint:fromView,得到方块上边缘的中点在self.view坐标系中的坐标。

运行demo:




现在已经达到了我们的需求了?不过好似和最开头的效果图存在一点点差异,或许细心的你已经看出来,方块在水平方向上一直保持不变!这又是为什么呢?



优化调整

现在我们解决上面水平方向不变的小问题,回顾一下,我们初始化连接行为时,使用的是以下初始化方法:

_attach = [[UIAttachmentBehavior alloc] initWithItem:_plateView attachedToAnchor:CGPointMake(200, 100)];

这个方法,其实是将“绳子”和小方块的中心点连接起来了!如下图,连接的是C点,并非我们画线的B点




因此我们需要把连接点改为C点。UIAttachmentBehavior给我们提供了另一个方法:

_attach = [[UIAttachmentBehavior alloc] initWithItem:_plateView offsetFromCenter:UIOffsetMake(0, -30) attachedToAnchor:CGPointMake(200, 100)];

这个方法比原来的多了一个offsetFromCenter的参数,类型为一个UIOffset结构体,结构体包含了水平和竖直方向上的偏移量,从D点到C点,只要向上移动30个单位,也就是在竖直方向上偏移-30即可。

现在再运行项目:




完美!



添加手势

给方块添加拖动手势:

UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]initWithTarget:self action:@selector(pan:)];
[_plateView addGestureRecognizer:pan];

当用户拖动view时,会回调pan:方法,我们在此方法中,改变方块的位置:

- (void)pan:(UIGestureRecognizer *)pan
{pan.view.center = [pan locationInView:self.view];
}

运行项目,尝试 拖动方块......



这是什么鬼!或许你忘记了上一篇Blog中的"碰撞的背后"说过不应该修改view的transform属性,当然我们也不应该修改center属性。

那么我们就在开始拖动的时候,移除所有的行为,当拖动结束之后再把行为添加回去,将pan:函数修改为如下:

- (void)pan:(UIGestureRecognizer *)pan
{switch (pan.state) {case UIGestureRecognizerStateBegan:[_animator removeAllBehaviors];break;case UIGestureRecognizerStateChanged:pan.view.center = [pan locationInView:self.view];break;case UIGestureRecognizerStateEnded:[_animator addBehavior:_gravity];[_animator addBehavior:_attach];break;default:break;}
}

再次运行项目,拖动滑块看看!


微调微调!

上一篇讲到,我们可以配置物体的属性,即弹性、密度、阻力等等,这个大家可以尝试各个属性不同的值,看看对方块运动产生什么影响。示例:

    UIDynamicItemBehavior* itemBehaviour = [[UIDynamicItemBehavior alloc] initWithItems:@[_plateView]];itemBehaviour.elasticity = 0.6;[_animator addBehavior:itemBehaviour];


封装

先下载啦:https://github.com/dolacmeng/JXDynamicsDemo

我做了简单封装,只要下面几行代码,即可将带绳子的方块添加到项目中:

JXDynamics *dy = [[JXDynamics alloc] initWithFrame:CGRectMake(110, 200, 50, 50)];
[self.view addSubview:dy];
[dy setUpWithAnchor:CGPointMake(100, 100) inView:self.view];

如果想响应点击事件:

dy.tapBlock = ^{NSLog(@"tap!");
};


JXDynamics是UIView子类,你可以在上面添加UI控件,例如UILabel:

UILabel *label = [[UILabel alloc] initWithFrame:dy.bounds];
label.text = @"Hello";
label.textAlignment = NSTextAlignmentCenter;
[dy addSubview:label];

效果如图:



当然,你也可以自定义类继承自JXDynamics,详见demo。


原创文章,转载标注出处:http://blog.csdn.net/dolacmeng/article/details/52301621


相关文章:

IIS7 配置PHP服务器

安装PHP Manager&#xff1a; 1&#xff09;访问 http://phpmanager.codeplex.com/releases/view/69115 下载PHP Manager。其中&#xff0c;x86 为32位 Windows 系统使用&#xff0c;x64 为64位 Windows 系统使用&#xff0c;请根据使用的 Windows 系统情况下载 2&#xff09;下…

在文本框中提示用户输入内容格式的方法

希望达到的效果&#xff1a; 方法一&#xff1a;鼠标点击文本框时文字消失 <input id"login_name" type"text" οnblur"javascript:check_login_name();" οnfοcus"if(this.value支持英文及数字组合) this.value;this.style.color#000&…

saltstack实现haproxy+keepalived负载均衡+高可用(二)

一键部署haproxykeepalived实现负载均衡高可用 实验环境&#xff1a; &#xff01;&#xff01;&#xff01;&#xff01; 特别注意&#xff1a; www.westos.org为test1的minion名字 test1: 172.25.1.11 nginx master minion test2: 172.25.…

iOS开发技巧(系列十八:扩展UIColor,支持十六进制颜色设置)

新建一个Category&#xff0c;命名为UIColorHex&#xff0c;表示UIColor支持十六进制Hex颜色设置。 UIColorHex.h文件&#xff0c; #import <UIKit/UIKit.h> #define RGBA_COLOR(R, G, B, A) [UIColor colorWithRed:((R) / 255.0f) green:((G) / 255.0f) blue:((B) / 255…

iOS顶部菜单栏

封装的一个顶部菜单栏&#xff0c;使用懒加载&#xff08;选择后加载当前页及前后各一页&#xff09;&#xff0c;自适应标题长度。 下载&#xff1a; Github&#xff1a;https://github.com/dolacmeng/JXChannelSegment 用法&#xff1a; //init Segment segment [[JXSegme…

Mac环境下svn的使用

CHENYILONG BlogMac环境下svn的使用 Mac环境下svn的使用 在Windows环境中&#xff0c;我们一般使用TortoiseSVN来搭建svn环境。在Mac环境下&#xff0c;由于Mac自带了svn的服务器端和客户端功能&#xff0c;所以我们可以在不装任何第三方软件的前提下使用svn功能&#xff0c;不…

zabbix简介及基本安装(一)

zabbix简单介绍&#xff1a; 官网&#xff1a;可以进官网查看一下&#xff1a;https://www.zabbix.com/cn/ //英语能力有限的读者可以将由上角的语言调成汉语方便查看 功能&#xff1a;网络监控、服务器监控、云监控、服务监控等。 介绍&#xff1a;zabbix&#xff08;[…

顺序表应用6:有序顺序表查询

顺序表应用6&#xff1a;有序顺序表查询 Time Limit: 7MS Memory Limit: 700KBSubmit StatisticProblem Description 顺序表内按照由小到大的次序存放着n个互不相同的整数&#xff08;1<n<20000)&#xff0c;任意输入一个整数&#xff0c;判断该整数在顺序表中是否存在。…

LA 5717枚举+最小生成树回路性质

1 /*LA 57172 《训练指南》P3433 最小生成树的回路性质4 在生成的最小生成树上&#xff0c;新增一条边e(u,v)5 若原图上u到v的路径的最大边大于e&#xff0c;则删除此边&#xff0c;加上e&#xff0c;否则不变。6 7 若原图上u到v的路径的最大边的产生&#xff1a;BFS/DFS都可 &…

【Runtime】动态添加方法demo

今天写一个小demo来演示下runtime的消息转发和动态添加方法。 一般项目中都会有保存当前登录用户资料的需求&#xff0c;我们可以直接将登录成功后的用户信息分别保存到NSUserDefaults中&#xff1a; [def setObject:"JackXu" forKey:"UserName"];[def set…

Zabbix之主机的添加与删除(二)

接着上一篇内容继续讲&#xff1a; 环境等都是建立在上一篇内容的基础上的&#xff0c;见https://blog.csdn.net/weixin_41922887/article/details/83755271 redhat6 test1: 172.25.1.11 zabbix-agent redhat7 server: 172.25.1.1 …

昨天网上感觉好冷,睡在席子上都是感觉打哈欠

今天爸妈也是休息一天&#xff0c;中午听说是要到外婆家去&#xff0c;不过家里就不知道会不会有一个团圆聚餐了&#xff0c;还有伴月就是国庆解&#xff0c;那时就要吧这个推掉值班的事情做好下。 转载于:https://www.cnblogs.com/bkchengzheng/p/5874328.html

几行代码实现神奇移动的过渡动画

1.效果如图&#xff1a; 2.实现&#xff1a; 假设需求为如上图&#xff0c;点击ViewController01后&#xff0c;ViewController01上的两张图片&#xff0c;移动到ViewContoller02中&#xff0c;其实两个ViewController的View上分别放置了这两张图&#xff0c;JXMagicMove就是实…

php字符串处理函数相关操作

<?php//获取tech和98426这两个字符串$str "http://info.meadin.com/tech/98426_1.shtml";echo $newstr substr($str,7,strlen($str)); //info.meadin.com/tech/98426_1.shtml$arr explode(/,$newstr);$num $arr[1];//tech$user strstr($arr[2], _, true); /…

介绍Zabbix的两种监控模式(主动模式和被动模式)

Zabbix agent检测分为两种模式&#xff1a;主动模式和被动模式 被动模式&#xff0c;也是默认的Zabbix监控模式&#xff0c;被动模式是相对于proxy来说的。proxy主动发送数据就是主动模式&#xff0c;proxy等待server的请求再发送数据就是被动模式。主动模式有个好处就是可以有…

【Step By Step】将Dotnet Core部署到Docker下

一、使用.Net Core构建WebAPI并访问Docker中的Mysql数据库 这个的过程大概与我之前的文章《尝试.Net Core—使用.Net Core Entity FrameWork Core构建WebAPI&#xff08;一&#xff09;》一致。 但是在我们这里&#xff0c;由于docker中无法部署sql server&#xff0c;所以我采…

ipad无法与itunes同步,提示因为这台电脑不再被授权使用在此ipad上购买的项目解决方案...

1、iOS设备用数据线连接到电脑&#xff1b;2、打开电脑上的iTunes 11&#xff0c;按CtrlB键调出菜单栏&#xff0c;按CtrlS键调出边栏&#xff1b;在边栏的 设备 下面看到你的iOS设备&#xff1b;3、点击菜单栏中的商店&#xff0c;点击 对这台电脑授权&#xff0c;输入你的App…

iOS根据字节数截取字符串

最近项目有个需求&#xff0c;文章的作者最多显示7个中文字&#xff0c;英文字符算半个中文字&#xff0c;超过7个中文字&#xff0c;则显示&#xff1a;前7个中文字...&#xff0c;使用NSString的length方法&#xff0c;不管是一个中文还是英文字符&#xff0c;都是返回1。因此…

搭建Zabbix分布式监控

1、实现zabbix监控nginx 实验环境&#xff1a; server1 172.25.1.1 server redhat7 test1 172.25.1.11 agent redhat7 在“手动添加”主机的基础上进行扩展 开启服务&#xff1a; [rootserver ~]# systemctl…

Codeforces Round #372 (Div. 2), problem: (B) Complete the Word

水题&#xff0c;每次截取长度为26的字符串&#xff0c;然后直接进行修改就可以 然而本弱渣昨天wa看很久 include<bits/stdc.h> using namespace std; int n,c; int ans[30]; int main() { string s; cin>>s; int tt0; int ns.size(); if(n<26) { cout<<&…

百练 2973 Skew数 解题报告

思路&#xff1a; 计算出每一个skew数的不同位数表示的权值&#xff0c;然后用该位与权值相乘。用int数组来装权值&#xff0c;用char数组来装skew数。 代码&#xff1a; #include<stdio.h> #include<string.h> int main() {int i, k, sum;int base[32];char skew[…

【Python】在Mac系统中安装Pygame

我们通过Homebrew来安装Pygame&#xff0c;Homebrew是Mac OSX上的软件包管理工具&#xff0c;如果还没安装Homebrew&#xff0c;将以下命令粘贴至终端先安装Homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install…

zabbix部署onealert云警告平台

onealert告警功能 告警 All In One&#xff0c;支持微信、邮箱、短信、APP、电话告警支持接入 Zabbix、Nagios、阿里云、腾讯云、监控宝等等告警信息灵活的分配策略&#xff0c;可灵活的分配告警信息发送给相关人员微信、邮箱、app 等告警方式全部免费实验环境&#xff1a; 首…

StringBuilder、StringBuffer、String区别

相信大家对 String 和 StringBuffer 的区别也已经很了解了&#xff0c;但是估计还是会有很多同志对这两个类的工作原理有些不清楚的地方&#xff0c;今天重新把这个概念给大家复习一下&#xff0c;顺便牵出 J2SE5.0 里面带来的一个新的字符操作的类—— StringBuilder &#xf…

Class中isAssignableFrom() 方法

看Spring源码的时候看到这个方法&#xff1a; 1 protected WebApplicationContext createWebApplicationContext(ServletContext sc) { 2 Class<?> contextClass determineContextClass(sc); 3 if (!ConfigurableWebApplicationContext.class.isAs…

【iOS】iOS10.3新增API:应用内评分

1、需求 在iOS10.3以前&#xff0c;APP引导用户评分时需要跳转到AppStore中操作&#xff0c;并且AppStore在国内有时加载会较慢&#xff0c;即便有的用户想给APP好评&#xff0c;但是等了几秒钟评分页面还没加载出来从而放弃。在iOS10.3中&#xff0c;苹果新增了APP内评分的新…

dhcp动态主机配置协议

dhcp简介&#xff1a; 动态主机设置协议&#xff08;Dynamic Host Configuration Protocol&#xff0c;DHCP&#xff09;是一个局域网的网络协议&#xff0c;使用UDP协议工作&#xff0c;计算机网络应用层协议。 主要有两个用途&#xff1a;用于内部网或网络服务供应商自动分配…

JSONP--解决ajax跨域问题

取不到数据&#xff01; 上周客户新买了服务器&#xff0c;原本在旧的服务器上放着客户的Web主页信息和一个后台程序(asp.net)&#xff0c;在客户的主页中有一个动态显示最新消息的处理&#xff0c;这个处理就是通过ajax异步从那个后台程序中取得的。由于又购买了新的服务器&am…

OC基本数据存储方式

/** 一,数据存储 常用方式(5种) 1,XML属性列表 -- 保存在Doucuments文件夹 2,偏好设置(NSUserDefault)-- Library/Preference 需要配合writetoFile来配合使用,保存到沙盒 3,归档(NSKeyedArchiver) -- 实现coding协议 4,sqlite --使用sqlite语法操作数据库 5,Core Data -- 由系统…

Xcode可重用代码块code snippets

一. 关于code snippets 通过Xcode的重用代码块&#xff08;code snippets&#xff09;可快速输入预设好的常用代码模板&#xff0c;如通过键入 hystrong 系统会直接替代为 property(nonatomic,strong) <#class#> <#name#>;二. 添加方法 如下图进行选择&#…