こんにちは、すんです!
AutoLayoutでビューを動的追加するときには制約をモリモリ書かないと行けません。なので、Utilクラスを作成して便利なメソッドを用意しておきましょう。AutoLayoutの一番基本のコードとなるので、AutoLayout初学者の参考になればと思います。
見通し
今回はAndroidのLinearLayout風に右向きや下向きに簡単にaddできるような操作クラスを作成します。
以下、呼び出し元のコードです。
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、制約、の順に呼んでやらないと上手くいかないので注意してください。
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系の操作が便利ということを教えていただきました。
もっと、いい方法があるよって方がいればコメントください。