Как заставить Interface Builder учитывать внутренний размер содержимого пользовательского представления в макете на основе ограничений?

Построитель интерфейсов в XCode 4.5 учитывает встроенный размер содержимого для некоторых представлений, например. NSButton, но я не могу убедить его уважать его в моих собственных подвидах. Это заставляет IB добавлять дополнительные ограничения, пытаясь принудительно отрисовать макет в IB, что затем приводит к тому, что внутренние размеры не используются при запуске программы.

Например, рассмотрим кнопку, расположенную по центру окна, и пользовательское представление, расположенное по центру окна…

Ограничения IB для центрированного NSButton

Ограничения IB для центрированного NSView

Вы можете видеть, что пользовательское представление получает четыре ограничения, по-видимому, потому, что IB не знает встроенныйContentSize представления. Вы можете изменить, какие дополнительные ограничения добавляются, например. вы можете заставить его быть шириной и высотой, но вы не можете удалить их.

Я справляюсь с этим сейчас, ища и удаляя дополнительные ограничения в моем awakeFromNib, но должен быть лучший способ сделать это.


person bitmusher    schedule 05.12.2012    source источник
comment
вы нашли решение этой проблемы? :)   -  person Kukosk    schedule 30.12.2012
comment
Примечание на 2019 год: теперь есть решение этой проблемы. Ответ ниже   -  person Fattie    schedule 03.09.2019


Ответы (3)


Установите внутренний размер содержимого заполнителя — «догадку», если хотите — в Interface Builder.

  1. Выберите свой собственный вид.
  2. Показать инспектор размера (Shift5).
  3. Измените раскрывающийся список «Внутренний размер» с «По умолчанию (определено системой)» на «Заполнитель».
  4. Введите разумные предположения о ширине и высоте вашего представления во время выполнения.

Эти ограничения удаляются во время компиляции, то есть они не будут влиять на ваше работающее приложение, а механизм компоновки добавит ограничения по мере необходимости во время выполнения, чтобы соблюдать intrinsicContentSize вашего представления.

person ravron    schedule 29.08.2014
comment
Но не лучший способ. Было бы здорово, если бы он мог запускать метод intrinsicContentSize и использовать результат непосредственно в Interface Builder, как это делается с IBDesignable. - person Iulian Onofrei; 10.05.2017
comment
Примечание на 2019 год: теперь есть решение этой проблемы. Ответ ниже. Вы используете invalidateIntrinsicContentSize - person Fattie; 03.09.2019

Как на самом деле это сделать, 2019

import UIKit

@IBDesignable class TagPerson: ShadowRoundedImageView {

    override var intrinsicContentSize: CGSize {
        var s = super.intrinsicContentSize
        s.height = 40
        s.width = 40
        return s
    }

    override func prepareForInterfaceBuilder() {
        invalidateIntrinsicContentSize()
    }

}

Однако есть проблема. Xcode глючит. Иногда вы можете сбросить его:

Вышеупомянутое, конечно, будет работать безупречно во время выполнения. Но он случайно не работает в конструкторе интерфейсов (даже с 11+).

Чтобы запустить цикл, попробуйте

  1. Обычное «Обновить все представления»

  2. Прикрепите и удалите бессмысленное ограничение к одному из ваших встроенных представлений размера. (Я заметил, что если у вас есть несколько из них, сделать это с одним обычно достаточно, чтобы запустить цикл Xcode, тогда все они работают.)

  3. И наконец:

В Xcode есть функция "внутренний заполнитель размера".

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

Выберите один или несколько элементов собственного размера. Переключите причудливую штуку-заполнитель вперед и назад несколько раз. Часто это приводит к циклу, и тогда представление будет работать правильно.

В худшем случае перезапуск Xcode с обычной очисткой — иногда все заработает.

person Fattie    schedule 03.09.2019
comment
Для меня добавление @IBDesignable было необходимо, чтобы заставить Xcode учитывать размер содержимого. - person Balázs Vincze; 30.01.2020
comment
@BalázsVincze, один важный момент, IBDesignable в основном безнадежно сломан в текущем Xcode: / к сожалению, мы обнаруживаем, что он полностью терпит неудачу в любых нетривиальных историях - грустно - person Fattie; 31.01.2020
comment
Ох, какой позор... К счастью, XIB, в котором я использовал свое пользовательское представление, был действительно тривиальным. - person Balázs Vincze; 31.01.2020

Хорошо, дело здесь в том, чтобы заставить Xcode использовать intrinsicContentSize вашего пользовательского представления в IB.

Этого можно добиться, добавив замещающее представление внутри вашего пользовательского представления в IB с фиксированной шириной и высотой (вы также можете центрировать его по горизонтали и по вертикали).

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

Затем выберите свой собственный вид и нажмите "Размер по размеру содержимого" в меню «Правка» в IB. На этом этапе все дополнительные ограничения, определяющие размер, можно будет удалить, оставив только ограничения позиционирования.

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

Таким образом, IB изменит размер вашего пользовательского представления в соответствии с представлением-заполнителем, а Autolayout будет зависеть от переопределения вашего представления - (CGSize)intrinsicContentSize во время выполнения, чтобы определить размер вашего пользовательского представления.

Последним шагом является удаление представления-заполнителя, чтобы ваше представление могло правильно отображать его содержимое и размер:

   - (void)viewDidLoad
    {
        [super viewDidLoad];
        [_placeholderView removeFromSuperview];
    }

Я знаю, что это хак, но, надеюсь, он вам поможет.

person Mariam K.    schedule 17.04.2013
comment
@Fattie Я полностью с вами согласен, в настоящее время с опцией заполнителя и огромным улучшением автомакета / IB это совершенно не нужно. Но имейте в виду, что я ответил на этот вопрос еще в 2013 году, когда ничего из этого еще не существовало;) - person Mariam K.; 04.09.2019
comment
@МариамК. возможно, пометьте свой ответ как устаревший (2019), как вы написали в своем комментарии выше. - person Bruno Bieri; 19.09.2019