IOS 7では、ビューとトップレイアウトガイドの間に制約を追加できるようになりました。これは、iOS7のステータスバーオフセットの問題を解決するのに非常に役立つと思います(特にビューにナビゲーションバーがない場合)。
ストーリーボードファイルに、この種の制約を簡単に追加できます。コントロールキーを押したままビューをコンテナにドラッグすると、「トップスペースからトップレイアウトガイドへ」オプションが表示されます。
ただし、xibファイルで同じ操作を行うと、このオプションは表示されなくなります。
では、このような制約をxibファイルに追加する方法はありますか?または、コードで追加する必要がありますか?
次の例を参照してください。これは間違いなく問題の解決に役立ちます。これは http://developer.Apple.com から取得しました。
[button setTranslatesAutoresizingMaskIntoConstraints: NO];
id topGuide = myViewController.topLayoutGuide;
NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings (button, topGuide);
[myViewController.view addConstraints:
[NSLayoutConstraint constraintsWithVisualFormat: @"V:[topGuide]-20-[button]"
options: 0
metrics: nil
views: viewsDictionary]
];
これが私の代替ソリューションです。
UIViewをピボットとして見つけ、その上部レイアウト制約をコンテナの上部に固定された垂直スペースに設定します。
Controlキーを押しながらこのレイアウト制約をIBOutletとしてドラッグします。たとえば、
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;
最後に、次のようにUIViewControllerのviewWillLayoutSubviewsメソッドをオーバーライドします
- (void)viewWillLayoutSubviews
{
[super viewWillLayoutSubviews];
self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT;
}
他のすべてのビューの上部の制約は、このピボットビューに基づいており、すべて完了しています:)
IOS 9以降では、topLayoutGuideのanchors
を使用してより簡単に行うこともできます。
view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true
[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;
もちろん、プログラムでビューとtop layout guide
またはbottom layout guide
の間に制約を追加できるだけでなく、ビューとtop and bottom layout guide
間の制約を削除してアクセスすることもできます- KVConstraintExtensionsMaster ライブラリ。
// create containerView
UIView *containerView = [UIView prepareNewViewForAutoLayout];
[containerView setBackgroundColor:[UIColor brownColor]];
[self.view addSubview:containerView];
// To add Top and Bottom Layout Guide constraint of containerView
[self applyTopLayoutGuideConstraintToView:containerView withPadding:0];
[self applyBottomLayoutGuideConstraintToView:containerView withPadding:50];
// To access top Layout Guide Constraint and update it's constant value.
NSLayoutConstraint *topLayoutGuideConstraint = [self accessAppliedTopLayoutGuideConstraintFromView:containerView];
topLayoutGuideConstraint.constant = 50;
// To access bottom Layout Guide Constraint and update it's constant value with animation
NSLayoutConstraint *bottomLayoutGuideConstraint = [self accessAppliedBottomLayoutGuideConstraintFromView:containerView];
bottomLayoutGuideConstraint.constant = 80;
[self.view updateModifyConstraintsWithAnimation:NULL]; // call this for animation
// To remove Top and Bottom Layout Guide constraint of containerView
[self removeAppliedTopLayoutGuideConstraintFromView:containerView];
[self removeAppliedBottomLayoutGuideConstraintFromView:containerView ];
今までXCode 6を使用しても、.xibファイルのトップレイアウトガイドにコントロールを揃えることはできません。代わりに、私は別の方法を使用しています。
まず、インターフェイスビルダーでは、コントロールをviewcontrolerのビューの上部の境界線に合わせます。
次に、viewDidLoadメソッドでいくつかの制約を置き換えて、メインビューではなく上部のレイアウトガイドに合わせます。
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *constraints = self.view.constraints;
for (NSLayoutConstraint *constraint in constraints) {
if ( (constraint.firstItem == self.view) && (constraint.firstAttribute == NSLayoutAttributeTop) ) {
NSLayoutConstraint *newConstraint = [self constraint:constraint replaceFirstItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
[self.view removeConstraint:constraint];
[self.view addConstraint:newConstraint];
} else if ( (constraint.secondItem == self.view) && (constraint.secondAttribute == NSLayoutAttributeTop) ) {
NSLayoutConstraint *newConstraint = [self constraint:constraint replaceSecondItemBy:self.topLayoutGuide attribute:NSLayoutAttributeBottom];
[self.view removeConstraint:constraint];
[self.view addConstraint:newConstraint];
}
}
}
- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceFirstItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
UILayoutPriority priority = constraint.priority;
NSLayoutRelation relation = constraint.relation;
id secondItem = constraint.secondItem;
NSLayoutAttribute secondAttribute = constraint.secondAttribute;
CGFloat multiplier = constraint.multiplier;
CGFloat constant = constraint.constant;
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:newItem attribute:newAttribute relatedBy:relation toItem:secondItem attribute:secondAttribute multiplier:multiplier constant:constant];
newConstraint.priority = priority;
return newConstraint;
}
- (NSLayoutConstraint*)constraint:(NSLayoutConstraint*)constraint replaceSecondItemBy:(id)newItem attribute:(NSLayoutAttribute)newAttribute {
UILayoutPriority priority = constraint.priority;
id firstItem = constraint.firstItem;
NSLayoutAttribute firstAttribute = constraint.firstAttribute;
NSLayoutRelation relation = constraint.relation;
CGFloat multiplier = constraint.multiplier;
CGFloat constant = constraint.constant;
NSLayoutConstraint *newConstraint = [NSLayoutConstraint constraintWithItem:firstItem attribute:firstAttribute relatedBy:relation toItem:newItem attribute:newAttribute multiplier:multiplier constant:constant];
newConstraint.priority = priority;
return newConstraint;
}
インターフェイスビルダーで定義したオブジェクトを置き換えるため、これは最善の方法ではないと思います。しかし、それは私たちが考えることができる代替方法かもしれません。
XIBに表示されない理由は、その状況ではView Controller階層の知識がないためであると思いますが、ストーリーボードでは、IBがビューが存在するView Controller階層からのガイドを示していることがあります。すなわち、UINavigationControllerに含まれている場合、トップレイアウトガイドがナビゲーションツールバーの下にあると判断できます。
Swift 4のCao Huu Locの答え
extension NSLayoutConstraint {
func constraintReplacing(firstItemWith newFirstItem: UILayoutSupport, withAttribute newFirstAttribute: NSLayoutAttribute) -> NSLayoutConstraint {
return NSLayoutConstraint(item: newFirstItem, attribute: newFirstAttribute, relatedBy: relation, toItem: secondItem, attribute: secondAttribute, multiplier: multiplier, constant: constant)
}
func constraintReplacing(secondItemWith newSecondItem: UILayoutSupport, withAttribute newSecondAttribute: NSLayoutAttribute) -> NSLayoutConstraint {
return NSLayoutConstraint(item: firstItem as Any, attribute: firstAttribute, relatedBy: relation, toItem: newSecondItem, attribute: newSecondAttribute, multiplier: multiplier, constant: constant)
}
}
class YourViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
for constraint in view.constraints {
if constraint.firstItem === view && constraint.firstAttribute == .top {
let newConstraint = constraint.constraintReplacing(firstItemWith: topLayoutGuide, withAttribute: .bottom)
view.removeConstraint(constraint)
view.addConstraint(newConstraint)
}
if constraint.secondItem === view && constraint.secondAttribute == .top {
let newConstraint = constraint.constraintReplacing(secondItemWith: topLayoutGuide, withAttribute: .bottom)
view.removeConstraint(constraint)
view.addConstraint(newConstraint)
}
}
}
}