文系プログラマの勉強ノート

スマホアプリ開発やデザインなどについて勉強したことをまとめています

【Xcode】なるべくコードを書かずにAutoLayoutを使ってアニメーションする

AutoLayoutを使ってアニメーションする方法を調べたところ、VisualFormatを使ってコード上でAutoLayoutの制約を書く方法が多く見つかりました。

しかし、VisualFormatで制約を書くのはなかなか複雑ですので、そこはIBで済ませてなるべくコードを書かないでやってみました。

今回作るもの

Moveボタンを押すと緑色の四角が上下に動くアニメーションを作ります。

f:id:an3714106:20160415234815g:plain:w200

作成手順

画面を作る

storyboardでView(緑色の四角)やButtonを配置していきます。
まず、View(緑色の四角)に下記の制約を追加します。

  • 幅・高さ 200
  • 垂直方向の制限:superviewから40の位置
  • 水平方向の制限:superviewに対し中央


f:id:an3714106:20160415235501p:plain



「垂直方向の制限:superviewから40の位置」はpriorityがデフォルトの1000になっています。


f:id:an3714106:20160415235545p:plain



次に、View(緑色の四角)に「垂直方向の制限:superviewから200の位置」を追加します。追加後、この制約のpriorityを900(先ほどの制約より小さい値)に設定します。これによりAutoLayoutの警告が発生しなくなります。


f:id:an3714106:20160415235921p:plain


Buttonについては割愛します。適当にお願いします。


変数、メソッドと結びつける

View(緑色の四角)やButtonを変数、メソッドと結びつけていきます。
moveViewはView(緑色の四角)自身と、upperConstraintは「垂直方向の制限:superviewから40の位置」と、underConstraintは「垂直方向の制限:superviewから200の位置」と結びつけてください。

@property (weak, nonatomic) IBOutlet UIView *moveView;  // 動かすビュー
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *upperConstraint;   // 上位置
@property (strong, nonatomic) IBOutlet NSLayoutConstraint *underConstraint;   // 下位置


f:id:an3714106:20160416000433p:plain


また、Buttonをタップしたときのメソッドを設定しておきます。

- (IBAction)onMoveButton:(id)sender {
}

 

コードを書く

viewDidLoadで初期化をしておきます。
ビューを上下どちらに動かすかを判定するtoBottomプロパティを追加し、最初は下に動かしたいのでYESにしておきます。
また、コード上でAutoLayoutを設定するために、動かすビューのtranslatesAutoresizingMaskIntoConstraintsプロパティをNOにします。

@property BOOL toBottom;    // 移動方向

(中略)

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.toBottom = YES;
    self.moveView.translatesAutoresizingMaskIntoConstraints = NO;
}


次に、Buttonを押したときに呼ばれるメソッドを下記のように実装します。

- (IBAction)onMoveButton:(id)sender {
    if (self.toBottom) {
        // 上から下へ動かす
        self.upperConstraint.active = NO;
        self.underConstraint.active = YES;
        [UIView animateWithDuration:0.3f
                              delay:0.f
                            options:UIViewAnimationOptionCurveEaseInOut
                         animations:^{
                             [self.view layoutIfNeeded];
                         }
                         completion:nil];
    } else {
        // 下から上へ動かす
        self.upperConstraint.active = YES;
        self.underConstraint.active = NO;
        [UIView animateWithDuration:0.3f
                              delay:0.f
                            options:UIViewAnimationOptionCurveEaseInOut
                         animations:^{
                             [self.view layoutIfNeeded];
                         }
                         completion:nil];
    }
    self.toBottom = !self.toBottom;
}


やっていることは、Buttonを押すたびにアニメーションをつけて垂直方向の制約を切り替えているだけです。
ポイントは

  • [UIView animateWithDuration:] のanimationsブロック内で [self.view layoutIfNeeded]; を呼ぶこと(呼ばないとアニメーションしません)
  • NSLayoutConstraintのプロパティは strong にしておくこと(通常IBOutletはweakにしますが、strongでないと active = NO を呼んだ後解放されてしまいます)

です。