AutoLayoutでAndroid風にビューを追加する(iOS)


こんにちは、すんです！
AutoLayoutでビューを動的追加するときには制約をモリモリ書かないと行けません。なので、Utilクラスを作成して便利なメソッドを用意しておきましょう。AutoLayoutの一番基本のコードとなるので、AutoLayout初学者の参考になればと思います。

# 見通し
今回はAndroidのLinearLayout風に右向きや下向きに簡単にaddできるような操作クラスを作成します。


以下、呼び出し元のコードです。

```objc

ViewSetter *viewSetter = [[ViewSetter alloc] initWithUIView : parentView];

for(int i = 0; i < 3; i++) {
    // ラベルを生成して下向きに追加
    UILabel *label = [[UILabel alloc] initWithFrame : CGRectZero];
    [viewSetter addViewDown : label
                     height : 40
                  marginTop : 0
                 marginLeft : 0
                marginRight : 0
                            ];
}
        
```

イニシャライズで親ビューを渡し高さ40のラベルをマージンなしで下向きに追加しています。

追加するViewはRectを与えずに生成し、高さや幅の決定はAutoLayoutに任せます。

#View操作クラス
以下がView操作クラスになります。下向き追加のメソッドを定義しています。制約の中身の順番はどうでもいいのですが、setTranslatesAutoresizingMaskIntoConstraints、addSubview、制約、の順に呼んでやらないと上手くいかないので注意してください。


```objc:ViewSetter.m

@interface ViewSetter()
/// 親ビュー
@property (strong, nonatomic) UIView *parentView;
/// 前回追加したビュー
@property (strong, nonatomic) UIView *prevView;

@end

@implementation ViewSetter

- (id)initWithUIView : (UIView*) parentView
{
    if (self = [super init]) {
        _parentView = parentView;
    }
    return self;
}

-(void) addViewDown : (UIView*) subView
             height : (int) height
          marginTop : (int) marginTop
         marginLeft : (int) marginLeft
       margintRight : (int) marginRight
{
    [subView setTranslatesAutoresizingMaskIntoConstraints:NO];
    
    // ビューを追加
    [self.parentView addSubview:subView];
    
    // 上面の制約
    if (self.prevView) {
    
        // 前回追加したビューの真下に合わせる
        [self.parentView addConstraint:[NSLayoutConstraint constraintWithItem : subView
                                                                 attribute : NSLayoutAttributeTop
                                                                 relatedBy : NSLayoutRelationEqual
                                                                    toItem : self.prevView
                                                                 attribute : NSLayoutAttributeBottom
                                                                multiplier : 1.0
                                                                  constant : marginTop]];
    } else {
    
        // 親ビューのTopに合わせる
        [self.parentView addConstraint : [NSLayoutConstraint constraintWithItem : subView
                                                               attribute : NSLayoutAttributeTop
                                                               relatedBy : NSLayoutRelationEqual
                                                                  toItem : self.parentView
                                                               attribute : NSLayoutAttributeTop
                                                              multiplier : 1.0
                                                                constant : marginTop]];
    }
    
    // 高さの制約
    [_ParentView addConstraint: [NSLayoutConstraint constraintWithItem : subView
                                                              attribute : NSLayoutAttributeHeight
                                                              relatedBy : NSLayoutRelationEqual
                                                                 toItem : nil
                                                              attribute : NSLayoutAttributeHeight
                                                             multiplier : 1.0
                                                               constant : height]];
    
    // 左面の制約
    [self.parentView addConstraint:[NSLayoutConstraint constraintWithItem:subView
                                                             attribute : NSLayoutAttributeLeft
                                                             relatedBy : NSLayoutRelationEqual
                                                                toItem : self.parentView
                                                             attribute : NSLayoutAttributeLeft
                                                            multiplier : 1.0
                                                              constant : marginLeft]];
    // 右面の制約
    [self.parentView addConstraint : [NSLayoutConstraint constraintWithItem : subView
                                                             attribute : NSLayoutAttributeRight
                                                             relatedBy : NSLayoutRelationEqual
                                                                toItem : self.parentView
                                                             attribute : NSLayoutAttributeRight
                                                            multiplier : 1.0
                                                              constant : marginRight]];

    
    // prevViewを設定します。
    self.prevView = subView;
}

```

#最後に
+ Swiftでもほぼ同じコードが書けると思います。
+ 同様にして右向き追加のメソッドや、高さや幅を%で指定できるような引数にして追加メソッドを用意すると便利かなと思います。
+ 本当はクラスメソッドで書きたかったのですが、前回追加したビューを親ビューが覚えていないから無理かなーという感じでこういうクラスを作りました。
+ UIView自体に追加用のメソッドを拡張するのが良さそうな気もしますが、また別のお話ということで。
+ VisualFormatは文字列でビューを指定するのがなんとなく怖いのでスルーしています。
+ ScrollView内で使うときには一番最後に下面の制約を書いてやらないとスクロールできません。
+ コメントにて**Masonry**というライブラリを使うとAutoLayout系の操作が便利ということを教えていただきました。

もっと、いい方法があるよって方がいればコメントください。