帶你了解UIKit動(dòng)力學(xué)

一、簡(jiǎn)單介紹

1.什么是UIDynamic
UIDynamic是從iOS 7開(kāi)始引入的一種新技術(shù),隸屬于UIKit框架可以認(rèn)為是一種物理引擎,能模擬和仿真現(xiàn)實(shí)生活中的物理現(xiàn)象如:重力、彈性碰撞等現(xiàn)象

2.物理引擎的價(jià)值
廣泛用于游戲開(kāi)發(fā),經(jīng)典成功案例是“憤怒的小鳥(niǎo)”,讓開(kāi)發(fā)人員可以在遠(yuǎn)離物理學(xué)公式的情況下,實(shí)現(xiàn)炫酷的物理仿真效果提高了游戲開(kāi)發(fā)效率,產(chǎn)生更多優(yōu)秀好玩的物理仿真游戲

3.知名的2D物理引擎
Box2d
Chipmunk

二、使用步驟

要想使用UIDynamic來(lái)實(shí)現(xiàn)物理仿真效果,大致的步驟如下:

1.創(chuàng)建一個(gè)物理仿真器(順便設(shè)置仿真范圍)
2.創(chuàng)建相應(yīng)的物理仿真行為(順便添加物理仿真元素)
3.將物理仿真行為添加到物理仿真器中開(kāi)始仿真

三、相關(guān)說(shuō)明

1.三個(gè)概念

  • 誰(shuí)要進(jìn)行物理仿真?
      物理仿真元素(Dynamic Item)
  • 執(zhí)行怎樣的物理仿真效果?怎樣的動(dòng)畫效果?
      物理仿真行為(Dynamic Behavior)
  • 讓物理仿真元素執(zhí)行具體的物理仿真行為
      物理仿真器(Dynamic Animator)

2.物理仿真元素
注意:
不是任何對(duì)象都能做物理仿真元素
不是任何對(duì)象都能進(jìn)行物理仿真

物理仿真元素要素:
任何遵守了UIDynamicItem協(xié)議的對(duì)象
UIView默認(rèn)已經(jīng)遵守了UIDynamicItem協(xié)議,因此任何UI控件都能做物理仿真

UICollectionViewLayoutAttributes類默認(rèn)也遵守UIDynamicItem協(xié)議

3.物理仿真行為

(1)UIDynamic提供了以下幾種物理仿真行為

  • UIGravityBehavior:重力行為

  • UICollisionBehavior:碰撞行為

  • UISnapBehavior:捕捉行為

  • UIPushBehavior:推動(dòng)行為

  • UIAttachmentBehavior:附著行為

  • UIDynamicItemBehavior:動(dòng)力元素行為

(2)物理仿真行為須知
上述所有物理仿真行為都繼承自UIDynamicBehavior,所有的UIDynamicBehavior都可以獨(dú)立進(jìn)行組合使用多種行為時(shí),可以實(shí)現(xiàn)一些比較復(fù)雜的效果

4.物理仿真器

(1)物理仿真器須知
它可以讓物理仿真元素執(zhí)行物理仿真行為
它是UIDynamicAnimator類型的對(duì)象
(2)UIDynamicAnimator的初始化

- (instancetype)initWithReferenceView:(UIView *)view;

view參數(shù):是一個(gè)參照視圖,表示物理仿真的范圍

5.物理仿真器的說(shuō)明

(1)UIDynamicAnimator的常見(jiàn)方法

//移除之前添加過(guò)的所有物理仿真行為  
- (void)addBehavior:(UIDynamicBehavior *)behavior; 
//移除之前添加過(guò)的所有物理仿真行為 
- (void)removeBehavior:(UIDynamicBehavior *)behavior; 
//添加1個(gè)物理仿真行為 
- (void)removeAllBehaviors; 

(2)UIDynamicAnimator的常見(jiàn)屬性

 //參照視圖 
@property (nonatomic, readonly) UIView* referenceView;  
//添加到物理仿真器中的所有物理仿真行為
@property (nonatomic, readonly, copy) NSArray* behaviors;
//是否正在進(jìn)行物理仿真
@property (nonatomic, readonly, getter = isRunning) BOOL running;
//代理對(duì)象(能監(jiān)聽(tīng)物理仿真器的仿真過(guò)程,比如開(kāi)始和結(jié)束)
@property (nonatomic, assign) id 

四、案例介紹

先看效果吧

  • UIGravityBehavior:重力行為
UIGravityBehavior.gif
  • UICollisionBehavior:碰撞行為
UICollisionBehavior.gif
  • UISnapBehavior:捕捉行為
UISnapBehavior.gif
  • UIPushBehavior:推動(dòng)行為
UIPushBehavior.gif
  • 復(fù)合效果
復(fù)合效果.gif

最后是代碼

#import <UIKit/UIKit.h>

@interface SecondViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIView *blueView;
@property (weak, nonatomic) IBOutlet UIView *orangeView;
@property (weak, nonatomic) IBOutlet UISegmentedControl *segmented;
@property (weak, nonatomic) IBOutlet UIView *redView;
@property (nonatomic,strong) UIDynamicAnimator *animator;

@end

#import "SecondViewController.h"

@interface SecondViewController ()
@property (nonatomic,strong)UISnapBehavior *snapBehavior;
@property (nonatomic,strong)UIPushBehavior *pushBehavior;
@property (nonatomic,strong)UIAttachmentBehavior *attachmentBehavior;

@end

@implementation SecondViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.blueView.transform =  CGAffineTransformMakeRotation(M_PI_4);
    self.segmented.transform = CGAffineTransformMakeRotation(-M_PI / 8);
    
    
    if (!_pushBehavior) {
        _pushBehavior = [[UIPushBehavior alloc]initWithItems:@[_blueView] mode:UIPushBehaviorModeContinuous];
    }
    
    _pushBehavior.active = YES;
    _pushBehavior.pushDirection = CGVectorMake(10.0f, 10.0f);
    _pushBehavior.magnitude = 1.0f;
    [self.animator addBehavior:_pushBehavior];
    
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:    (UIEvent *)event {
    _pushBehavior.active = NO;
    
    //創(chuàng)建重力行為
    UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc]init];
    [gravityBehavior addItem:self.blueView];
    [gravityBehavior addItem:self.orangeView];
    [gravityBehavior addItem:self.segmented];
    gravityBehavior.gravityDirection = CGVectorMake(-0.3f, 1.0f);
    //加速度
    gravityBehavior.magnitude = 3;
    //創(chuàng)建碰撞行為
    UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc]init];
    //碰撞類型為元素和邊界
    collisionBehavior.collisionMode = UICollisionBehaviorModeEverything;
    
    CGFloat Y = self.view.frame.size.height - CGRectGetHeight(self.redView.frame);
    CGFloat X = self.view.frame.size.width;
    CGFloat height = self.view.frame.size.height;
    
    //設(shè)置紅色的View為底邊界,左邊框跟右邊框作為邊界
    [collisionBehavior addBoundaryWithIdentifier:@"collision1" fromPoint:CGPointMake(0,Y) toPoint:CGPointMake(X, Y)];
    [collisionBehavior addBoundaryWithIdentifier:@"collision2" fromPoint:CGPointMake(0, 0) toPoint:CGPointMake(0, height)];
    [collisionBehavior addBoundaryWithIdentifier:@"collision3" fromPoint:CGPointMake(X,0) toPoint:CGPointMake(X, height)];
    
    [collisionBehavior addItem:self.blueView];
    [collisionBehavior addItem:self.segmented];
    [collisionBehavior addItem:self.orangeView];
    [self.animator addBehavior:collisionBehavior];
    [self.animator addBehavior:gravityBehavior];
    
    UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.blueView]];
    [itemBehavior setElasticity:0.5];
    [self.animator addBehavior:itemBehavior];
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapGesture:)];
    [self.view addGestureRecognizer:tap];
}
- (void)tapGesture:(UITapGestureRecognizer *)gesture
{
    CGPoint tapPoint = [gesture locationInView:self.view];
    if (_snapBehavior) {
        [self.animator removeBehavior:_snapBehavior];
        _snapBehavior = nil;
    }
    _snapBehavior = [[UISnapBehavior alloc]initWithItem:self.blueView snapToPoint:tapPoint];
    _snapBehavior.action = ^(){
        NSLog(@"UISnapBehavior 在執(zhí)行");
    };
    _snapBehavior.damping = 0.9;
    [self.animator addBehavior:_snapBehavior];
}
- (UIDynamicAnimator *)animator{
    if (_animator == nil) {
        _animator = [[UIDynamicAnimator alloc]init];
    }
    return _animator;
}

- (void)panGestureRecognizer:(UIPanGestureRecognizer *)gesture
{
    CGPoint location = [gesture locationInView:self.view];
    CGPoint imageLocation = [gesture locationInView:self.orangeView];
    switch (gesture.state) {
        case UIGestureRecognizerStateBegan:
        {
            NSLog(@"touch position %@",NSStringFromCGPoint(location));
            NSLog(@"loction in image %@",NSStringFromCGPoint(imageLocation));
            [self.animator removeAllBehaviors];
            
            UIOffset centerOffset = UIOffsetMake(imageLocation.x - CGRectGetMidX(self.orangeView.bounds), imageLocation.y - CGRectGetMidY(self.orangeView.bounds));
            _attachmentBehavior = [[UIAttachmentBehavior alloc]initWithItem:self.orangeView offsetFromCenter:centerOffset attachedToAnchor:location];
            _attachmentBehavior.damping = 0.5;
            _attachmentBehavior.frequency = 0.8;
            [self.animator addBehavior:_attachmentBehavior];
            
        }
            break;
        case UIGestureRecognizerStateEnded:
        {
            [self.animator removeBehavior:_attachmentBehavior];
        }
            break;
        default:
        {
            [_attachmentBehavior setAnchorPoint:[gesture locationInView:self.view]];
        }
            break;
    }
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

/*
 #pragma mark - Navigation
 
 // In a storyboard-based application, you will often want to do a little preparation before navigation
 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
 // Get the new view controller using [segue destinationViewController].
 // Pass the selected object to the new view controller.
 }
 */

@end
 

UIKit動(dòng)力學(xué)的部分介紹完了.
最開(kāi)始項(xiàng)目中只是用到了重力跟碰撞行為,參考學(xué)習(xí)了:UIDynamic 詳細(xì)用法 中的案例.然后自己又展開(kāi)了解了下UIKit動(dòng)力學(xué)的知識(shí),把捕捉行為,推動(dòng)行為加了進(jìn)去,做個(gè)完善.整理了一下.就是這樣.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 簡(jiǎn)介 什么是UIDynamic UIDynamic是從iOS 7開(kāi)始引入的一種新技術(shù),隸屬于UIKit框架 可以認(rèn)...
    JonesCxy閱讀 245評(píng)論 0 1
  • 本文中所有代碼演示均有GitHub源碼,點(diǎn)擊下載 UIDynamic簡(jiǎn)介 簡(jiǎn)介:UIKit動(dòng)力學(xué)最大的特點(diǎn)是將現(xiàn)實(shí)...
    si1ence閱讀 10,481評(píng)論 8 79
  • UIKit動(dòng)力學(xué)最大的特點(diǎn)是將現(xiàn)實(shí)世界動(dòng)力驅(qū)動(dòng)的動(dòng)畫引入了UIKit,比如重力,鉸鏈連接,碰撞,懸掛等效果,即將2...
    BarleyZ閱讀 1,368評(píng)論 0 49
  • 周末到了,閑來(lái)無(wú)事,我決定去登山。山不高,也不是盛夏,綠色還沒(méi)有那么多,不過(guò)陽(yáng)光還挺毒的。我上午10點(diǎn)到的山腳下,...
    一只睡不著的考拉閱讀 308評(píng)論 0 0
  • 1時(shí)間 2靠規(guī)模 3高回報(bào)
    快跑水果閱讀 268評(píng)論 0 0

友情鏈接更多精彩內(nèi)容