Чи є спосіб додати обмеження між видом та верхнім посібником макета у файлі xib?


75

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

У файлі розкадровки я можу легко додати такі обмеження. Просто утримуйте клавішу управління, а потім перетягніть подання до контейнера, він покаже опцію "Посібник із верхнього простору до верхнього макета".

введіть тут опис зображення

Але коли я виконую ту саму операцію у файлі xib, ця опція зникає.

введіть тут опис зображення

Отже, чи є спосіб додати такий тип обмежень у файли xib? Або я повинен додати їх із кодом?


Я б рекомендував задати "ще одне питання" як окреме питання.
hpique

1
У мене виникає протилежне запитання - чи є спосіб обмежити верхній край контейнера замість Top Guide Layout у розкадруванні?
Павло Алексєєв

Відповіді:


77

Вам слід звернутися до наступного прикладу, це точно допоможе вам у вирішенні вашої проблеми. Я отримав це з 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 для перегляду подання контролера, і я хочу, щоб у випадку iOS7 він починався з 20, а для iOS6 - з 0. Я використовую код вище (замість кнопки я використовую свій погляд), але це не так працюючі можуть знати, як це вирішити?
Нузжат Зарі

@NuzhatZari ви можете явно перевірити версію системи тут stackoverflow.com/questions/7848766 / ...
joslinm

14
Було б непогано, якби ці обмеження можна було встановити на Xcode і для XIB ... Xcode повинен просто надавати його (незалежно від знання ієрархії контролера подання).
Рікардо Санчес-Саес,

1
Чи є спосіб розмістити всі підпрограми VC під рядком стану, без обмежень? Подобається використовувати верхній посібник з макетування в раскадровках?
Користувач123335511231

14

Ось моє альтернативне рішення.

Знайдіть UIView як опорну точку, встановіть його верхнє обмеження макета на фіксований вертикальний простір до верхньої частини контейнера.

Control-Перетягніть це обмеження макета як IBOutlet, наприклад

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

Нарешті, просто перевизначте метод viewWillLayoutSubviews UIViewController, як показано нижче

- (void)viewWillLayoutSubviews
{
    [super viewWillLayoutSubviews];

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

Усі основні обмеження для інших поглядів базуються на цьому поворотному вигляді, все готово :)


Це погано справляється з переміщенням topLayoutGuide (скажімо, користувач перебуває у дзвінку або використовує GPS або щось інше спричиняє збільшення topLayoutGuide)
анонім

9

З iOS 9 ви також можете зробити це простіше за допомогою topLayoutGuide anchors:

  • Стрімкий 3

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

  • ObjC

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


найкраще рішення на сьогоднішній день!
Kappe

6

До цього часу, навіть використовуючи 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

Звичайно, Ви можете не тільки додати обмеження між поданням та 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 ];

5

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


3
Це не має значення. У цьому вся суть цих путівників. Ви просто вирівнюєтеся до них, і якщо цей ВК знаходиться всередині навігаційного контролера, він має певний верхній розмір напрямного макета. Якщо він представлений як модальний ВК без видимого рядка стану, тоді його розмір дорівнює 0 і т. Д. Він може і повинен мати можливість викласти відносно своїх напрямних, не знаючи, який їх розмір (на час проектування).
CIFilter 02

0

Відповідь Цао Хуу Лока стрімкими 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)
            }
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.