Не удалось загрузить IBDesignable xib в Интерфейсном Разработчике

У меня есть файл xib (childXib), связанный с его пользовательским файлом UIView swift через его владельца.

Вот как я инициализирую свой собственный UIView:

// init for IBDesignable
override init(frame: CGRect) {
    super.init(frame: frame)

    let view = loadViewFromNib()
    view.frame = bounds

    addSubview(view)
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
    addSubview(loadViewFromNib())
}

func loadViewFromNib() -> UIView {

    let bundle = NSBundle(forClass: self.dynamicType)
    let nib = UINib(nibName: "CommentCellView", bundle: bundle)
    let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

    return view
}

Когда я хочу добавить этот xib (childXib) в другой xib (parentXib), я получаю следующие ошибки:

ошибка: IB Designables: не удалось отобразить экземпляр MyRootView: агент выдал исключение.

Где MyRootView - это файл, связанный с parentXib

ошибка: IB Designables: не удалось обновить состояние автоматического макета: агент вызвал исключение «NSInternalInconsistencyException»: не удалось загрузить NIB в пакете: «NSBundle (loaded)» с именем «MyIBDesignableCustomViewFilename»

Где MyIBDesignableCustomViewFilename - это файл, связанный с childXib.

Когда я отлаживаю его, щелкая Debug в Custom class из Identity inspector, он не работает из этой строки:

let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView

Все xib файлы находятся в Copy Bundle Resources в Build Phases.

Есть идеи, что случилось?


person Nico    schedule 03.02.2016    source источник
comment
Использует ли ваш xib подкласс UIView? Если это так, вы можете попробовать применить его к этому классу.   -  person AMayes    schedule 03.02.2016
comment
Да, все они являются подклассами UIView   -  person Nico    schedule 03.02.2016
comment
Тогда попробуйте let view = nib.instantiateWithOwner(self, options: nil)[0] as! MyCustomView   -  person AMayes    schedule 04.02.2016
comment
@Nico Вы добавляете CommentCellView.xib в свой проект, а не просто копируете?   -  person Allen    schedule 06.02.2016
comment
Вы имеете в виду Copy Bundle Resources из Build Phases?   -  person Nico    schedule 06.02.2016
comment
@Nico db.tt/JhX9F0xE Я создал для вас образец проекта. Если вы удалите или переименуете CommentCellView.xib в проекте, вы увидите, что ошибки могут быть воспроизведены, как вы упомянули.   -  person Allen    schedule 06.02.2016
comment
Ok. Я попробовал ваш проект, добавил еще xib в качестве контейнера (вместо раскадровки), все работает. Затем я добавил два других xib, и у меня возникла проблема. Не могу понять, что это. Вот ссылка, если вы хотите это проверить: bit.ly/20MtrnN   -  person Nico    schedule 06.02.2016
comment
@Nico Я только что проверил. В LikesCountView.swift вы пропустили @IBOutlet weak var likeButton: UIButton! и @IBAction func likeAction (sender: AnyObject) {} Я обновил содержание приведенной выше ссылки. Вы можете загрузить снова и выполнить поиск по ключевым словам // Отсутствующие ранее для частей, которые я добавил.   -  person Allen    schedule 06.02.2016


Ответы (3)


Первый шаг:

Я расскажу вам о IBDesignable и IBInspectable и покажу вам, как воспользоваться преимуществами новой функции. Нет лучшего способа разработать функцию, чем создать демонстрацию. Итак, мы вместе создадим настраиваемый интерфейс под названием «Радуга».

IBDesignable и IBInspectable

С помощью IBDesignable и IBInspectable разработчики могут создавать интерфейс (или представление), который отображается в Интерфейсном Разработчике в реальном времени. В общем, чтобы применить эту новую функцию, все, что вам нужно сделать, это создать визуальный класс, создав подкласс UIView или UIControl, а затем префикс имени класса с помощью ключевого слова @IBDesignable в Swift. Если вы используете Objective-C, вместо этого вы используете макрос IB_DESIGNABLE. Вот пример кода на Swift:

@IBDesignable 
class Rainbow: UIView {
}

В более старых версиях Xcode вы можете редактировать определенные пользователем атрибуты времени выполнения, чтобы изменить свойства объекта (например, layer.cornerRadius) в Интерфейсном Разработчике. Проблема в том, что вам нужно ввести точное название свойств. IBInspectable делает шаг вперед. Когда вы добавляете к свойству визуального класса префикс IBInspectable, свойство будет открыто для Interface Builder, так что вы можете изменить его значение очень простым способом:

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

Опять же, если вы разрабатываете свое приложение на Swift, вам нужно просто добавить к выбранному свойству префикс @IBInspectable. Вот пример фрагмента кода:

@IBInspectable var firstColor: UIColor = UIColor.blackColor()
 {
     // Update your UI when value changes
 }



@IBInspectable var firstColor: UIColor = UIColor.blackColor()
{
     // Update your UI when value changes
 }

Создание проекта Xcode

Давайте начнем с создания нового проекта в Xcode, выберем в качестве шаблона приложение с одним представлением и назовем его RainbowDemo. В этом проекте мы будем использовать Swift в качестве языка программирования, поэтому не забудьте выбрать его при создании проекта.

После завершения выберите Main.storyboard в навигаторе проекта и перетащите объект View из библиотеки объектов в контроллер представления. Измените его цвет на # 38334C (или любой другой цвет, который вы хотите), а также установите его размер 600 на 434. Затем поместите его в центр основного вида. Не забудьте изменить цвет основного представления на тот же цвет, что и объект просмотра. Совет: если вы хотите изменить значения цвета RGB для своего кода, просто откройте свою цветовую палитру и переключитесь на вкладку «Ползунки», чтобы изменить значения RGB.

Запутались? Не стоит беспокоиться. Вы поймете, что я имею в виду, после демонстрации проекта.

С Xcode 6 вам необходимо настроить ограничения автоматического макета для представления, чтобы поддерживать все типы устройств iOS. Автоматическая компоновка в последней версии Xcode очень мощная. Для простых ограничений вы можете просто щелкнуть опцию Issues в меню Auto Layout и выбрать «Add Missing Contraints», и Xcode автоматически настроит ограничения макета для представления.

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

Создание настраиваемого класса представления

Теперь, когда вы создали представление в раскадровке, пора создать наш собственный класс представления. Мы будем использовать шаблон класса Swift для создания класса. Назовите его «Радуга».

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

Then insert the following code in the class:

import UIKit

class Rainbow: UIView {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
    }
}

Как упоминалось ранее, визуальный класс является подклассом UIView. Чтобы использовать наш настраиваемый класс при рендеринге в реальном времени, нам нужно переопределить оба инициализатора, как показано выше. Затем разделите представление, выбрав помощник редактора:

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

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

Реализация элементов управления IBDesignable

Первым шагом для включения элемента управления для рендеринга в реальном времени является установка пользовательского представления как Designable, добавив к имени класса префикс @IBDesignable:

@IBDesignable 
class Rainbow: UIView {
    ...
}

Как видите, это довольно просто. Но это простое ключевое слово значительно упростит вашу разработку. Далее мы добавим несколько свойств для настройки цвета кругов. Вставьте эти строки кода в класс Rainbow:

@IBInspectable var firstColor: UIColor = UIColor(red: (37.0/255.0), green: (252.0/255), blue: (244.0/255.0), alpha: 1.0)
@IBInspectable var secondColor: UIColor = UIColor(red: (171.0/255.0), green: (250.0/255), blue: (81.0/255.0), alpha: 1.0)
@IBInspectable var thirdColor: UIColor = UIColor(red: (238.0/255.0), green: (32.0/255)

Здесь мы заранее определяем для каждого свойства цвет по умолчанию и говорим ему перерисовывать представление каждый раз, когда пользователь изменяет его значение. Что наиболее важно, мы добавляем к каждому свойству префикс @IBInspectable. Если вы перейдете к инспектируемым атрибутам представления, вы должны визуально найти эти свойства:

Круто, правда? Указав свойства как IBInspectable, вы можете редактировать их визуально с помощью палитры цветов.

Хорошо, давайте перейдем к реализации основных методов класса Rainbow, который используется для рисования круга на экране. Вставьте в класс следующий метод:

func addOval(lineWidth: CGFloat, path: CGPathRef, strokeStart: CGFloat, strokeEnd: CGFloat, strokeColor: UIColor, fillColor: UIColor, shadowRadius: CGFloat, shadowOpacity: Float, shadowOffsset: CGSize) {

    let arc = CAShapeLayer()
    arc.lineWidth = lineWidth
    arc.path = path
    arc.strokeStart = strokeStart
    arc.strokeEnd = strokeEnd
    arc.strokeColor = strokeColor.CGColor
    arc.fillColor = fillColor.CGColor
    arc.shadowColor = UIColor.blackColor().CGColor
    arc.shadowRadius = shadowRadius
    arc.shadowOpacity = shadowOpacity
    arc.shadowOffset = shadowOffsset
    layer.addSublayer(arc)
}

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

Чтобы код был чистым и читаемым, мы создаем общий метод рисования полного или полукруга в соответствии с параметрами, предоставленными вызывающим. Рисовать круг или дугу с помощью класса CAShapeLayer довольно просто. Вы можете управлять началом и концом хода с помощью свойств strokeStart и strokeEnd. Изменяя значение stokeEnd от 0,0 до 1,0, вы можете нарисовать полный или частичный круг. Остальные свойства используются только для установки цвета обводки, цвета тени и т. Д. Подробную информацию обо всех свойствах, доступных в CAShapeLayer, вы можете найти в официальной документации.

Затем вставьте следующие методы в класс Rainbow:

override func drawRect(rect: CGRect) {
    // Add ARCs
    self.addCirle(80, capRadius: 20, color: self.firstColor)
    self.addCirle(150, capRadius: 20, color: self.secondColor)
    self.addCirle(215, capRadius: 20, color: self.thirdColor)
}

func addCirle(arcRadius: CGFloat, capRadius: CGFloat, color: UIColor) {
    let X = CGRectGetMidX(self.bounds)
    let Y = CGRectGetMidY(self.bounds)

    // Bottom Oval
    let pathBottom = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
    self.addOval(20.0, path: pathBottom, strokeStart: 0, strokeEnd: 0.5, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)

    // Middle Cap
    let pathMiddle = UIBezierPath(ovalInRect: CGRectMake((X - (capRadius/2)) - (arcRadius/2), (Y - (capRadius/2)), capRadius, capRadius)).CGPath
    self.addOval(0.0, path: pathMiddle, strokeStart: 0, strokeEnd: 1.0, strokeColor: color, fillColor: color, shadowRadius: 5.0, shadowOpacity: 0.5, shadowOffsset: CGSizeZero)

    // Top Oval
    let pathTop = UIBezierPath(ovalInRect: CGRectMake((X - (arcRadius/2)), (Y - (arcRadius/2)), arcRadius, arcRadius)).CGPath
    self.addOval(20.0, path: pathTop, strokeStart: 0.5, strokeEnd: 1.0, strokeColor: color, fillColor: UIColor.clearColor(), shadowRadius: 0, shadowOpacity: 0, shadowOffsset: CGSizeZero)

}

Реализация метода drawRect по умолчанию ничего не делает. Чтобы рисовать круги на виде, мы переопределяем метод для реализации нашего собственного кода рисования. Метод addCircle принимает три параметра: arcRadius, capRadius и цвет. arcRadius - это радиус круга, а capRadius - радиус закругленной крышки.

Метод addCircle использует UIBezierPath для рисования дуг и работает следующим образом:

First it draws a half circle at the bottom
Next it draws a full small circle at the edge of the arc.
Finally, it draws the other half of the circle

В методе drawRect мы вызываем метод addCircle три раза с разным радиусом и цветом. На этом рисунке показано, как нарисованы круги:  введите описание изображения здесь

Совет: если вам нужна дополнительная информация о UIBezierPath, вы можете ознакомиться с официальной документацией Apple.

Благодаря свойствам IBInspectable вы теперь можете изменять цвет каждого круга прямо в Интерфейсном Разработчике, не углубляясь в код:

Очевидно, вы можете дополнительно предоставить arcRadius как свойство IBInspectable. Я оставлю это вам в качестве упражнения.

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

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

для примера кода нажмите здесь: https://github.com/appcoda/Rainbow-IBDesignable-Demo

person princ___y    schedule 06.02.2016
comment
Боже, это безумие, количество усилий для одного ответа! С уважением, @prince. - person Morgan Wilde; 02.12.2016
comment
Отлично написано для IBDesignable, но не удалось удовлетворить запрос пользователя на файлы XIB. - person mobilemonkey; 24.03.2017
comment
@mobilemonkey согласился. Я не думаю, что этот ответ заслуживает награды. - person Sid; 11.08.2017
comment
dropbox.com/s/zi5ac3z1emz906v/ - person princ___y; 15.02.2019
comment
dropbox.com/sh/vsk7igc6776ycxb/ - person princ___y; 11.02.2021
comment
вопрос был о вовлеченных XIB - person ievgen; 23.03.2021

У меня была такая же проблема, и мне удалось ее исправить.

Swift 3

let bundle = Bundle(for: MyView.self)
let view = UINib(nibName: "MyView", bundle: bundle).instantiate(withOwner: self) as! MyView

Важный бит - это комплект

person NebulaFox    schedule 18.08.2017

Для обеих ошибок, как показано ниже:

error: IB Designables: Failed to render instance of ....
error: IB Designables: Failed to update auto layout status: The agent raised a "NSInternalInconsistencyException" exception: Could not load NIB in bundle ...

Я предлагаю провести небольшую быструю самопроверку, которая поможет выяснить, где следует решать проблемы:

  1. Проверьте, правильно ли добавлены файлы .xib в проект
  2. Проверьте, правильно ли установлено nibName, иногда здесь случается опечатка
  3. Проверьте, правильно ли подключены розетка и действие, включая реализацию кодов
person Allen    schedule 06.02.2016