iOS 7 by tutorials 学习笔记 01 - UIKit Dynamics and Motion Effects 上

UIKit Dynamics:集成到UIKit中的物理引擎,用于创建带有重力效果、弹跳效果的UI效果,让用户感受更加真实。

Motion Effects:用于创建“视觉差”效果,类似在iOS主界面上,左右倾斜手机的效果。

UIKit dynamics

学习UIKit dynamics最好的方法还是做一些实例。

创建名为DynamicsPlayground的Single View应用程序,并在ViewController.m中添加如下代码以创建一个灰色的正方形:

- (void)viewDidLoad {
    [super viewDidLoad];
    
    UIView *square = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    
    square.backgroundColor = [UIColor grayColor];
    [self.view addSubview:square];
}

添加重力效果

定义实例变量:

UIDynamicAnimator* _animator;
UIGravityBehavior* _gravity;

在viewDidLoad的最后添加重力效果:

    _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    _gravity = [[UIGravityBehavior alloc] initWithItems:@[square]];
    [_animator addBehavior:_gravity];
编译执行,你将会看到灰色的方块向下加速移动直到掉出屏幕:

这里用到了动态效果相关的两个类:

UIDynamicAnimator:作为UIKit物理效果的引擎,这个类保存着我们加到引擎中的所有动态效果,比如重力效果,并提供全局上下文。当我们创建animator实例时,需要传递一个reference view给引擎,animator使用这个view来设置坐标系。

UIGravityBehavior:为一个或多个item模拟重力效果。这里我们为square view模拟重力效果。

设置边界

通过设置边界,可以让灰色方块保持在屏幕上

定义变量:

UICollisionBehavior* _collision;
添加如下代码到viewDidLoad的最后:
    _collision = [[UICollisionBehavior alloc] initWithItems:@[square]];
    _collision.translatesReferenceBoundsIntoBoundary = YES;
    [_animator addBehavior:_collision];

处理碰撞

接下来,我们添加一个无法移动的障碍物,下落的方块撞到障碍物后,会改变其下落路线。

    UIView *barrier = [[UIView alloc] initWithFrame:CGRectMake(0, 300, 130, 20)];
    barrier.backgroundColor = [UIColor redColor];
    [self.view addSubview:barrier];
    
    _collision = [[UICollisionBehavior alloc] initWithItems:@[square, barrier]];
    _collision.translatesReferenceBoundsIntoBoundary = YES;
    [_animator addBehavior:_collision];

此时,关系图如下:


执行程序,灰色方块和红色障碍物发生了碰撞,但是和我们的期望有所区别,障碍物也被撞飞了。


隐形的边界

要到达障碍物不被撞飞,需要创建一个隐形的边界,宽度和位置和障碍物上沿一致。

将barrier从UICollisionBehavior中移除,这样障碍物就和dynamic引擎没有关联了。

_collision = [[UICollisionBehavior alloc] initWithItems:@[square]];
添加一个与红色障碍物上沿一致的边界,当灰色方框装上这条边界时,就会弹开。
    // add a boundary that coincides with the top edge
    CGPoint rightEdge = CGPointMake(barrier.frame.origin.x + barrier.frame.size.width, barrier.frame.origin.y);
    [_collision addBoundaryWithIdentifier:@"barrier" fromPoint:barrier.frame.origin toPoint:rightEdge];

碰撞action

通过动态行为的action属性,我们可以为动画的每一步指定一段可执行代码,如下代码可以让引擎在动画的每一步输出灰色方块的center和transform属性。

    _collision.action = ^{
        NSLog(@"%@, %@", NSStringFromCGAffineTransform(square.transform),
              NSStringFromCGPoint(square.center));
    };
编译执行程序,在方块下落过程中但是碰撞到障碍物之前,log如下,只有位移,没有旋转

2015-02-26 15:38:06.135 DynamicsPlayground[16183:168172] [1, 0, 0, 1, 0, 0], {150, 151}
2015-02-26 15:38:06.150 DynamicsPlayground[16183:168172] [1, 0, 0, 1, 0, 0], {150, 151}
2015-02-26 15:38:06.165 DynamicsPlayground[16183:168172] [1, 0, 0, 1, 0, 0], {150, 152}
2015-02-26 15:38:06.182 DynamicsPlayground[16183:168172] [1, 0, 0, 1, 0, 0], {150, 154}
碰撞到障碍物之后,方块开始旋转,log如下:

2015-02-26 15:38:06.550 DynamicsPlayground[16183:168172] [0.99997687, 0.0067999475, -0.0067999475, 0.99997687, 0, 0], {150, 250}
2015-02-26 15:38:06.566 DynamicsPlayground[16183:168172] [0.99839866, 0.056569785, -0.056569785, 0.99839866, 0, 0], {152, 250}
2015-02-26 15:38:06.583 DynamicsPlayground[16183:168172] [0.99434483, 0.10619935, -0.10619935, 0.99434483, 0, 0], {153, 250}
2015-02-26 15:38:06.600 DynamicsPlayground[16183:168172] [0.98785663, 0.15536803, -0.15536803, 0.98785663, 0, 0], {155, 251}

UIDyamicItem protocol定义如下,它使得引擎可以读取或修改对象的center和transform属性,使得引擎可以根据自己的计算修改这些属性。同时,引擎还可以访问bounds属性,以确定对象的大小。引擎使用这个数据来为对象创建边界。UIKit中另外一个遵循此协议的类是UICollectionViewLayoutAttributes,使得View Collection中的view之间可以以动画的方式切换。
@protocol UIDynamicItem <NSObject>
@property (nonatomic, readwrite) CGPoint center;
@property (nonatomic, readonly) CGRect bounds;
@property (nonatomic, readwrite) CGAffineTransform transform;
@end

碰撞通知

通过碰撞通知功能,我们的程序可以在对象发生碰撞时,收到来自引擎的通知。

修改ViewController.m

@interface ViewController () <UICollisionBehaviorDelegate>

@end
实现代理方法:

- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
    NSLog(@"Boundary contact occurred - %@", identifier);
}

执行程序可以看到以下log:

2015-02-26 16:11:22.289 DynamicsPlayground[17811:185503] Boundary contact occurred - barrier
2015-02-26 16:11:22.489 DynamicsPlayground[17811:185503] Boundary contact occurred - barrier
2015-02-26 16:11:22.939 DynamicsPlayground[17811:185503] Boundary contact occurred - (null)
2015-02-26 16:11:23.172 DynamicsPlayground[17811:185503] Boundary contact occurred - (null)
修改代码,当碰撞发生时,改变方块的颜色:

- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
    NSLog(@"Boundary contact occurred - %@", identifier);
    
    UIView *view = (UIView *)item;
    view.backgroundColor = [UIColor yellowColor];
    [UIView animateWithDuration:0.3 animations:^{
        view.backgroundColor = [UIColor grayColor];
    }];
}
程序执行效果如下:

配置item属性

修改viewDidLoad,修改灰色方块的弹性属性为0.6,这个值,越大,弹性越好,1.0代表不会损失动力。

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

运行时添加动态行为

修改ViewController.m,定义实例变量:

BOOL _firstContact;
修改collisionBehavior:beganContactForItem:withBoundaryIdentifier:atPoint方法,当灰色方块发生第一次碰撞时,创建第二个方块,将第二个方块加入到collision和gravity行为中。

- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{
    NSLog(@"Boundary contact occurred - %@", identifier);
    
    UIView *view = (UIView *)item;
    view.backgroundColor = [UIColor yellowColor];
    [UIView animateWithDuration:0.3 animations:^{
        view.backgroundColor = [UIColor grayColor];
    }];
    
    if (!_firstContact)
    {
        _firstContact = YES;
        
        UIView *square = [[UIView alloc] initWithFrame:CGRectMake(30, 0, 100, 100)];
        square.backgroundColor = [UIColor grayColor];
        [self.view addSubview:square];
        
        [_collision addItem:square];
        [_gravity addItem:square];
        
        UIAttachmentBehavior *attch = [[UIAttachmentBehavior alloc] initWithItem:view attachedToItem:square];
        [_animator addBehavior:attch];
    }
}
程序执行效果如下:







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值