Есть ли способ для Interface Builder визуализировать представления IBDesignable, которые не переопределяют drawRect:

Я очень редко переопределяю drawRect в своих подclassах UIView, обычно предпочитая устанавливать layer.contents изображениями предварительного рендеринга и часто используя несколько подслоев или подпунктов и манипулируя ими на основе входных параметров. Есть ли способ для IB сделать эти более сложные стеки представлений?

Спасибо, @zisoft за то, что я prepareForInterfaceBuilder меня на prepareForInterfaceBuilder . Там несколько нюансов с циклом рендеринга Interface Builder, которые были источником моих проблем и заслуживают внимания …

  1. Подтверждено: вам не нужно использовать -drawRect .

Работает настройка изображений в состояниях управления UIButton. Произвольные стеки слоев, похоже, работают, если учитывать несколько вещей …

  1. IB использует initWithFrame:

.. не initWithCoder . awakeFromNib также НЕ вызывается.

  1. init... вызывается только один раз за сеанс

То есть один раз для повторной компиляции всякий раз, когда вы вносите изменения в файл. Когда вы изменяете свойства IBInspectable, init снова не вызывается. Однако…

  1. prepareForInterfaceBuilder вызывается при каждом изменении свойства

Это похоже на то, что KVO на всех ваших IBInspectables, а также на другие встроенные свойства. Вы можете проверить это самостоятельно, _setup метод _setup , сначала только из вашего метода init.. Изменение IBInspectable не будет иметь эффекта. Затем добавьте вызов, чтобы подготовить prepareForInterfaceBuilder . Whahla! Обратите внимание, что для вашего кода во время выполнения, вероятно, потребуется некоторое дополнительное KVO, поскольку он не будет вызывать метод prepareForIB . Подробнее об этом ниже …

  1. init... слишком рано рисовать, устанавливать контент слоя и т. д.

По крайней мере, с моим подclassом UIButton , вызов [self setImage:img forState:UIControlStateNormal] не влияет на IB. Вам нужно вызвать его из prepareForInterfaceBuilder или через prepareForInterfaceBuilder hook.

  1. Когда IB не удается выполнить рендеринг, он не очищает наш компонент, а сохраняет последнюю успешную версию.

Может быть запутанным в моменты, когда вы вносите изменения, которые не влияют. Проверьте журналы сборки.

  1. Совет. Держите монитор активности поблизости.

Я получаю зависания все время на пару различных процессов поддержки, и они берут с собой всю машину. Примените Force Quit либерально.

(UPDATE: Это действительно не так, поскольку XCode6 вышел из бета-версии. Он редко висит)

ОБНОВИТЬ

  1. 6.3.1, похоже, не похож на KVO в версии IB. Теперь вам, похоже, нужен флаг, чтобы поймать Interface Builder и не настроить KVO. Это нормально, поскольку метод prepareForInterfaceBuilder эффективно использует KVO для всех свойств IBInspectable . К сожалению, это поведение не так зеркально отражено во время выполнения, что требует руководства KVO. См. Обновленный пример кода ниже.

Пример подclassа UIButton

Ниже приведен пример кода рабочего UIButton подclassа UIButton . ~~ Примечание. prepareForInterfaceBuilder самом деле не требуется, поскольку KVO прослушивает изменения наших соответствующих свойств и запускает перерисовку. ~~ UPDATE: см. Пункт 8 выше.

 IB_DESIGNABLE @interface SBR_InstrumentLeftHUDBigButton : UIButton @property (nonatomic, strong) IBInspectable NSString *topText; @property (nonatomic) IBInspectable CGFloat topTextSize; @property (nonatomic, strong) IBInspectable NSString *bottomText; @property (nonatomic) IBInspectable CGFloat bottomTextSize; @property (nonatomic, strong) IBInspectable UIColor *borderColor; @property (nonatomic, strong) IBInspectable UIColor *textColor; @end @implementation HUDBigButton { BOOL _isInterfaceBuilder; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { [self _setup]; } return self; } //--------------------------------------------------------------------- - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self _setup]; } return self; } //--------------------------------------------------------------------- - (void)_setup { // Defaults. _topTextSize = 11.5; _bottomTextSize = 18; _borderColor = UIColor.whiteColor; _textColor = UIColor.whiteColor; } //--------------------------------------------------------------------- - (void)prepareForInterfaceBuilder { [super prepareForInterfaceBuilder]; _isInterfaceBuilder = YES; [self _render]; } //--------------------------------------------------------------------- - (void)awakeFromNib { [super awakeFromNib]; if (!_isInterfaceBuilder) { // shouldn't be required but jic... // KVO to update the visuals @weakify(self); [self bk_addObserverForKeyPaths:@[@"topText", @"topTextSize", @"bottomText", @"bottomTextSize", @"borderColor", @"textColor"] task:^(id obj, NSDictionary *keyPath) { @strongify(self); [self _render]; }]; } } //--------------------------------------------------------------------- - (void)dealloc { if (!_isInterfaceBuilder) { [self bk_removeAllBlockObservers]; } } //--------------------------------------------------------------------- - (void)_render { UIImage *img = [SBR_Drawing imageOfHUDButtonWithFrame:self.bounds edgeColor:_borderColor buttonTextColor:_textColor topText:_topText topTextSize:_topTextSize bottomText:_bottomText bottomTextSize:_bottomTextSize]; [self setImage:img forState:UIControlStateNormal]; } @end 

Этот ответ связан с переопределением drawRect, но, возможно, он может дать некоторые идеи:

У меня есть пользовательский class UIView, который имеет сложные рисунки в drawRect. Вы должны заботиться о ссылках, которые недоступны во время разработки, то есть в UIApplication. Для этого я переопределяю prepareForInterfaceBuilder где я устанавливаю булевский флаг, который я использую в drawRect, чтобы различать время выполнения и время разработки:

 @IBDesignable class myView: UIView { // Flag for InterfaceBuilder var isInterfaceBuilder: Bool = false override init(frame: CGRect) { super.init(frame: frame) // Initialization code } required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } override func prepareForInterfaceBuilder() { self.isInterfaceBuilder = true } override func drawRect(rect: CGRect) { // rounded cornders self.layer.cornerRadius = 10 self.layer.masksToBounds = true // your drawing stuff here if !self.isInterfaceBuilder { // code for runtime ... } } } 

Вот как он выглядит в InterfaceBuilder:

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

Вам не нужно использовать drawRect, вместо этого вы можете создать свой пользовательский интерфейс в файле xib, загрузить его в initWithCoder и initWithFrame, и он будет отображаться в режиме реального времени в IB после добавления IBDesignable. Проверьте этот короткий учебник: https://www.youtube.com/watch?v=L97MdpaF3Xg

Я думаю, что layoutSubviews – самый простой механизм.

Вот пример (намного) в Swift:

 @IBDesignable class LiveLayers : UIView { var circle:UIBezierPath { return UIBezierPath(ovalInRect: self.bounds) } var newLayer:CAShapeLayer { let shape = CAShapeLayer() self.layer.addSublayer(shape) return shape } lazy var myLayer:CAShapeLayer = self.newLayer // IBInspectable proeprties here... @IBInspectable var pathLength:CGFloat = 0.0 { didSet { self.setNeedsLayout() }} override func layoutSubviews() { myLayer.frame = self.bounds // etc myLayer.path = self.circle.CGPath myLayer.strokeEnd = self.pathLength } } 

Я не тестировал этот fragment, но раньше использовал шаблоны. Обратите внимание, что использование ленивого свойства делегирует вычисляемое свойство для упрощения начальной конфигурации.

Чтобы уточнить ответ Хари Карам Сингха , это слайд-шоу объясняет далее:

http://www.splinter.com.au/presentations/ibdesignable/

Затем, если вы не видите, что ваши изменения отображаются в интерфейсе Builder, попробуйте эти меню:

  • Xcode-> Editor-> Автоматическое обновление представлений
  • Xcode-> Editor-> Обновить все представления
  • Xcode-> Editor-> Отладка выбранных представлений

К сожалению, отладка моего взгляда заморозила Xcode, но она должна работать для небольших проектов (YMMV).

В моем случае возникли две проблемы:

  1. Я не реализовал initWithFrame в пользовательском представлении: (Обычно initWithCoder: вызывается при инициализации через IB, но по какой-то причине initWithFrame: необходим только для IBDesignable . Не IBDesignable во время выполнения при реализации через IB)

  2. Мой пользовательский вид загружался из mainBundle : [NSBundle bundleForClass:[self class]] был необходим.

Я считаю, что вы можете реализовать prepareForInterfaceBuilder и сделать свою основную работу анимации, чтобы он появился в IB. Я сделал некоторые причудливые вещи с подclassами UIButton, которые выполняют свою собственную работу с основным слоем анимации, чтобы рисовать границы или фоны, и они прекрасно отображают рендеринг в построителе интерфейса, поэтому я предполагаю, что если вы подclassифицируете UIView напрямую, то prepareForInterfaceBuilder – это все вам нужно будет поступить иначе. Имейте в виду, что метод только когда-либо выполняется IB

Отредактировано для включения кода в соответствии с запросом

У меня что-то похожее, но не совсем так (извините, я не могу дать вам то, что я действительно делаю, но это работа)

 class BorderButton: UIButton { required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonInit() } override init(frame: CGRect) { super.init(frame: frame) commonInit() } func commonInit(){ layer.borderWidth = 1 layer.borderColor = self.tintColor?.CGColor layer.cornerRadius = 5 } override func tintColorDidChange() { layer.borderColor = self.tintColor?.CGColor } override var highlighted: Bool { willSet { if(newValue){ layer.backgroundColor = UIColor(white: 100, alpha: 1).CGColor } else { layer.backgroundColor = UIColor.clearColor().CGColor } } } } 

Я переопределяю как initWithCoder и initWithFrame потому что я хочу иметь возможность использовать компонент в коде или в IB (и, как утверждают другие ответы, вы должны реализовать initWithFrame чтобы сделать IB счастливым.

Затем в commonInit я настроил основной материал анимации, чтобы нарисовать границу и сделать ее красивой.

Я также реализую willSet для выделенной переменной, чтобы изменить цвет фона, потому что я ненавижу, когда кнопки рисуют границы, но не дают обратной связи при нажатии (я ненавижу, когда нажатая кнопка выглядит как нажатая кнопка)

Макрос Swift 3

 #if TARGET_INTERFACE_BUILDER #else #endif 

и class с функцией, которая называется, когда IB делает раскадровку

 @IBDesignable class CustomView: UIView { @IBInspectable public var isCool: Bool = true { didSet { #if TARGET_INTERFACE_BUILDER #else #endif } } override func prepareForInterfaceBuilder() { // code } } 

IBInspectable можно использовать с типами ниже

 Int, CGFloat, Double, String, Bool, CGPoint, CGSize, CGRect, UIColor, UIImage 
  • objective c - Обнаруживать, когда пользователь меняет настройки уведомлений приложения
  • В чем разница между ссылкой __weak и __block?
  • Почему NSNumber такие странные saveCounts?
  • @property сохранять, назначать, копировать, неатомически в Objective-C
  • Как определить глобальную переменную, доступ к которой можно получить в любом месте приложения?
  • Как подождать завершения асинхронного отправления?
  • NSNotificationCenter против делегирования (используя протоколы)?
  • Как Блок захватывает переменные за пределами своей охватывающей области?
  • Как включить ARC для одного файла
  • Генерация случайных чисел в Objective-C
  • Понимание побитового оператора AND
  • Interesting Posts

    Запись содержимого в новое окно с помощью JQuery

    Код Outcommented Facelets по-прежнему вызывает выражения EL, такие как # {bean.action ()} и вызывает javax.el.PropertyNotFoundException на # {bean.action}

    Windows 7 сохранить диалог висит – любые решения?

    Обнаружение кнопки домашнего нажатия в андроиде

    Оптимизация утечки памяти в JavaFX

    Как я могу остановить Windows 10 от ворчания меня, чтобы «восстановить настройки безопасности в Интернете»?

    Можете ли вы заставить компонент React перезапустить без вызова setState?

    link_to и remote => true + jquery: Как? Помогите?

    Как найти сертификат по отпечатку пальца в C #

    Push-уведомления, когда приложение закрыто

    EJB 3.1 @LocalBean vs no annotation

    Что такое файлы hiberfil.sys и pagefile.sys, и могу ли я безопасно их удалить?

    Разделение столбца строки dataframe на несколько разных столбцов

    Выделенная мышь и клавиатура на виртуальной машине VM

    Значение параметра ошибки преобразования для ‘null Converter’ – Зачем нужен конвертер в JSF?

    Давайте будем гением компьютера.