Как сделать так, чтобы пользовательский вид изменял размеры с помощью окна Cocoa Auto Layout? - PullRequest
71 голосов
/ 16 ноября 2011

У меня есть одно окно с одним настраиваемым представлением, и я хочу, чтобы настраиваемое представление изменяло размер окна так, чтобы оно полностью заполняло его в любое время. Если я напишу:

NSView *contentView = [self.window contentView];
CustomView *customView = [[CustomView alloc] initWithFrame:[contentView bounds]];
[contentView addSubview:customView];
[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeWidth
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeWidth
        multiplier:1
        constant:0]];
[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeHeight
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeHeight
        multiplier:1
        constant:0]];

Тогда окно не позволяет мне изменить его размер.
Если я добавлю:

[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

Тогда пользовательское представление не появляется (drawRect:, кажется, никогда не вызывается). Я пробовал разные способы (включая визуальный формат @"|[customview]|"), но всегда сталкиваюсь с одними и теми же проблемами. Я знаю, что это можно сделать с помощью более старой системы автоматического изменения размера:

[customView setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable];

но я хочу использовать систему Cocoa Auto Layout, и я хочу использовать ее для более сложных случаев (например, несколько пользовательских представлений, которые всегда заполняют окно).

Кто-нибудь знает, что не так и как я должен использовать систему Auto Layout, чтобы получить желаемый результат?

Ответы [ 4 ]

107 голосов
/ 17 ноября 2011

При автоматическом размещении существует (как минимум) три возможных способа ограничения представления, чтобы оно занимало представление содержимого всего окна, при необходимости изменяя размер.

Ограничения визуального формата в отношении суперпредставления

NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

[contentView addSubview:customView];

NSDictionary *views = NSDictionaryOfVariableBindings(customView);

[contentView addConstraints:
    [NSLayoutConstraint constraintsWithVisualFormat:@"H:|[customView]|"
        options:0
        metrics:nil
        views:views]];

[contentView addConstraints:
    [NSLayoutConstraint constraintsWithVisualFormat:@"V:|[customView]|"
    options:0
    metrics:nil
    views:views]];

Программные ограничения для ребер

(это должно быть эквивалентно визуальному формату выше)

+ (void)addEdgeConstraint:(NSLayoutAttribute)edge superview:(NSView *)superview subview:(NSView *)subview {
    [superview addConstraint:[NSLayoutConstraint constraintWithItem:subview
        attribute:edge
        relatedBy:NSLayoutRelationEqual
        toItem:superview
        attribute:edge
        multiplier:1
        constant:0]];
}

и

NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

[contentView addSubview:customView];

[[self class] addEdgeConstraint:NSLayoutAttributeLeft superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeRight superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeTop superview:contentView subview:customView];
[[self class] addEdgeConstraint:NSLayoutAttributeBottom superview:contentView subview:customView];

Программные ограничения дляразмер

NSView *contentView = [_window contentView];
MyView *customView = [[MyView alloc] initWithFrame:[contentView bounds]];
[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

[contentView addSubview:customView];

[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeWidth
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeWidth
        multiplier:1
        constant:0]];
[contentView addConstraint:
    [NSLayoutConstraint constraintWithItem:customView
        attribute:NSLayoutAttributeHeight
        relatedBy:NSLayoutRelationEqual
        toItem:contentView
        attribute:NSLayoutAttributeHeight
        multiplier:1
        constant:0]];

Третий подход - это тот, который указан в вопросе, и он может не сработать, если есть дополнительные ограничения.Например, без:

[customView setTranslatesAutoresizingMaskIntoConstraints:NO];

применяется также оригинальная маска авторазмера, что приводит к поведению, описанному в вопросе: окно не изменяется в размере.

Как упоминается в Regexident, вы можете использовать:

[_window visualizeConstraints:[contentView constraints]];

для отладки Auto Layout.Стоит также проверить вывод консоли.

47 голосов
/ 19 ноября 2011

@ Ответ Бавариуса хорош, я просто добавлю еще несколько вещей.

Очень важно научиться использовать встроенную поддержку отладки!Как и в случае большого развития, нереально надеяться, что вы всегда получите все правильно с первого выстрела.Это было серьезной проблемой для автоматической разметки, поэтому мы приложили много усилий для отладки.Кратко, шаги:

  1. Определите вид, который находится не в том месте.Вызов метода - [NSView _subtreeDescription] из gdb и / или передача аргументов -NSShowAllViews YES может помочь определить, какое представление является неправильным.
  2. Определить ограничение или ограничения, которые являются неправильными или отсутствуют.- [NSLayoutConstraint constraintsAffectingLayoutForOrientation:] помогает дать вам меньший набор ограничений для работы.- [NSWindow visualizeConstraints:] может помочь вам увидеть, что это за ограничения , равны , и вы можете увидеть из того, что из этого вам не нужно.Он также покажет вам, является ли ваш макет неоднозначным (недостаточно ограничений).
  3. Определите, откуда появилось неправильное ограничение.Шаблон «Какао-макет» в инструментах похож на инструмент «Утечки» - он покажет вам все события в жизненном цикле ограничения, например, где он был создан, добавлен в окно, изменен и т. Д. Итак, когда вы знаете, чтопроблема заключается в ограничении, используйте поле поиска в инструментах, чтобы отфильтровать и просмотреть только это ограничение, и вы сможете увидеть обратные следы для всех событий жизненного цикла и выяснить, где вы сделали то, что не хотели.

Обычно такой вопрос, который вы задали бы (мои материалы не работают!), Не будет достаточным для того, чтобы люди могли сказать, что не так, и это одна из причин, по которой важно использовать материал для отладки.Смотрите видео сессий WWDC 2011 (бесплатно для всех) и документы, чтобы узнать больше об этом.

Buuuuut Я действительно могу сказать, что пошло не так в этот раз.:-) До того, как вы отключили translatesAutoresizingMaskIntoConstraints, вы были более ограничены, чем хотели - ширина и высота вашего представления также были исправлены, поэтому размер окна не может быть изменен.ПОСЛЕ ТОГО, КАК вы его отключили, у вас была неоднозначная компоновка, потому что вы ни на что не смотрели!Вы сказали, насколько он должен быть (такой же, как у супервизора), но не , где должно было быть.

Кен

Какао-фреймворки, автор основного макета авто

5 голосов
/ 23 августа 2016

Вы можете создавать ограничения с помощью якорей макета в очень удобном для чтения формате:

Код Swift2

func fit(childView: UIView, parentView: UIView) {
    childView.translatesAutoresizingMaskIntoConstraints = false
    childView.topAnchor.constraintEqualToAnchor(parentView.topAnchor).active = true
    childView.leadingAnchor.constraintEqualToAnchor(parentView.leadingAnchor).active = true
    childView.trailingAnchor.constraintEqualToAnchor(parentView.trailingAnchor).active = true
    childView.bottomAnchor.constraintEqualToAnchor(parentView.bottomAnchor).active = true
}

Использование:

parrentView.addSubview(childView)
fit(childView, parentView: parrentView)
0 голосов
/ 19 декабря 2011

Я обнаружил, что -drawRect: не будет вызвано, если прямоугольник кадра равен 0,0,0,0.Нежелательные ограничения приводят к тому, что рамка становится 0,0,0,0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...