it-swarm.com.ru

Есть ли способ добавить ограничение между представлением и верхней версткой в ​​файле XIB?

В iOS 7 теперь мы можем добавить ограничение между представлением и верхним руководством по разметке, что, на мой взгляд, очень полезно для решения проблемы смещения строки состояния в iOS7 (особенно когда в представлении нет панели навигации).

В файле раскадровки я могу легко добавить этот тип ограничений. Просто удерживайте нажатой клавишу управления, затем перетащите вид в контейнер, он покажет опцию «Руководство по макету сверху вниз».

enter image description here

Но когда я делаю ту же операцию в xib-файле, эта опция исчезает.

enter image description here

Итак, есть ли способ добавить такого рода ограничения в файлы XIB? Или я должен добавить их с кодом?

73
Henry H Miao

Вы должны обратиться к следующему примеру, это определенно поможет вам в вашей проблеме. Я получил это от 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]
];
77
Neeraj Khede

Вот мое альтернативное решение.

Найдите UIView в качестве точки поворота, установите ограничение его верхнего макета на фиксированное вертикальное пространство до вершины контейнера.

Удерживая клавишу «Control», перетащите это ограничение макета как IBOutlet, например

@property (weak, nonatomic) IBOutlet NSLayoutConstraint *topLayoutConstraint;

Наконец, просто переопределите метод viewWillLayoutSubviews UIViewController, как показано ниже

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

    self.topLayoutConstraint.constant = [self.topLayoutGuide length] + YOUR_TOP_CONSTRSINT;
}

Основное ограничение всех остальных представлений основано на этом сводном представлении, все готово :)

14
ananfang

С iOS 9 вы также можете сделать это более просто с помощью anchors от topLayoutGuide:

  • Свифт 3 

view.topAnchor.constraint(equalTo: self.topLayoutGuide.bottomAnchor).isActive = true

  • ObjC

[controller.view.topAnchor constraintEqualToAnchor:controller.topLayoutGuide.bottomAnchor].active = YES;

9
Radu Vlad

Конечно, вы можете не только добавить ограничение между представлением и top layout guide или bottom layout guide программно, но также вы можете удалить и получить доступ к ограничению между представлением и top and bottom layout guide с помощью KVConstraintExtensionsMaster library.

// 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 ];
6
keshav vishwkarma

До сих пор, даже используя 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;
}

Думаю, это не лучший способ, потому что мы заменяем объекты, которые мы определяем в конструкторе интерфейсов. Но это может быть альтернативный способ, которым мы можем думать.

6
Cao Huu Loc

Я думаю, что причина, по которой они не отображаются в XIB, заключается в том, что в этой ситуации нет сведений об иерархии контроллера представлений, в то время как в раскадровке IB может определить, где находятся руководства из иерархии контроллеров представления, в которой находится представление. Т.е., если он содержится в UINavigationController, он может определить, что верхнее руководство по макету находится ниже панели инструментов навигации.

5
David Pettigrew

Цао Хуу Лок ответ с Swift 4

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)
            }
        }
    }
}
0
f3dm76