Оригинальное решение
- Я создал XIB и класс с именем SomeView (использовал одно и то же имя для удобства и читабельности). Я основал оба на UIView.
- В XIB я изменил класс «Владелец файла» на SomeView (в инспекторе удостоверений).
- Я создал выход UIView в SomeView.swift, связав его с представлением верхнего уровня в файле XIB (назвал его «представление» для удобства). Затем я добавил другие выходы к другим элементам управления в файле XIB по мере необходимости.
- в SomeView.swift я загрузил XIB внутри инициализатора «init with code». Нет необходимости присваивать что-либо «себе». Как только XIB загружен, все розетки подключены, включая представление верхнего уровня. Единственное, чего не хватает, это добавить вид сверху в иерархию видов:
,
class SomeView: UIView {
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
NSBundle.mainBundle().loadNibNamed("SomeView", owner: self, options: nil)
self.addSubview(self.view); // adding the top level view to the view hierarchy
}
...
}
Обратите внимание, что таким образом я получаю класс, который загружает себя из пера. Затем я мог бы использовать SomeView в качестве класса всякий раз, когда UIView можно использовать в проекте (в построителе интерфейса или программно).
Обновление - с использованием синтаксиса Swift 3
Загрузка xib в следующем расширении записывается как метод экземпляра, который затем может использоваться инициализатором, как показано выше:
extension UIView {
@discardableResult // 1
func fromNib<T : UIView>() -> T? { // 2
guard let contentView = Bundle(for: type(of: self)).loadNibNamed(String(describing: type(of: self)), owner: self, options: nil)?.first as? T else { // 3
// xib not loaded, or its top view is of the wrong type
return nil
}
self.addSubview(contentView) // 4
contentView.translatesAutoresizingMaskIntoConstraints = false // 5
contentView.layoutAttachAll(to: self) // 6
return contentView // 7
}
}
- Использование сбрасываемого возвращаемого значения, поскольку возвращаемое представление в основном не представляет интереса для вызывающей стороны, когда все выходы уже подключены.
- Это универсальный метод, который возвращает необязательный объект типа UIView. Если не удается загрузить представление, возвращается ноль.
- Попытка загрузить файл XIB с тем же именем, что и текущий экземпляр класса. Если это не удается, возвращается ноль.
- Добавление представления верхнего уровня в иерархию представлений.
- В этой строке предполагается, что мы используем ограничения для макета представления.
- Этот метод добавляет верхние, нижние, ведущие и конечные ограничения - прикрепляя представление к «себе» со всех сторон (подробности см .: https://stackoverflow.com/a/46279424/2274829 )
- Возвращение представления верхнего уровня
И метод вызывающей стороны может выглядеть так:
final class SomeView: UIView { // 1.
required init?(coder aDecoder: NSCoder) { // 2 - storyboard initializer
super.init(coder: aDecoder)
fromNib() // 5.
}
init() { // 3 - programmatic initializer
super.init(frame: CGRect.zero) // 4.
fromNib() // 6.
}
// other methods ...
}
- SomeClass - это подкласс UIView, который загружает свое содержимое из файла SomeClass.xib. Ключевое слово final не обязательно.
- Инициализатор, когда представление используется в раскадровке (не забудьте использовать SomeClass в качестве пользовательского класса представления раскадровки).
- Инициализатор, когда представление создается программно (т. Е. «Let myView = SomeView ()»).
- Использование фрейма со всеми нулями, поскольку это представление выложено с помощью автоматического макета. Обратите внимание, что метод init (frame: CGRect) {..} "не создается независимо, так как автоматическая разметка используется исключительно в нашем проекте.
- & 6. Загрузка файла XIB с использованием расширения.
Кредит: использование общего расширения в этом решении было вдохновлено ответом Роберта ниже.
Редактирование
Изменение «view» на «contentView», чтобы избежать путаницы. Также изменил индекс массива на ".first".
File's Owner
попасть в точку ... Спасибо!fromNib()
изнутриinit(coder aDecoder: NSCoder)
создает бесконечный цикл, так как загрузка Nib внутриfromNib()
метода вызывает:init(coder aDecoder: NSCoder)
Мой вклад:
Тогда назовите это так:
..или даже:
источник
Теперь возможность
-> Self
быстрого возврата помогает немного упростить это. Последний подтвержден на Swift 5.Если ваш
.xib
файл и подкласс имеют одинаковое имя, вы можете использовать:Если у вас есть собственное имя, используйте:
НОТА:
Если вы получаете сообщение об ошибке «представление типа YourType не найдено в ..», значит, вы не установили класс представления в
.xib
файлеВыберите свое представление в
.xib
файле, нажмитеcmd + opt + 4
и наclass
входе введите свой классисточник
let myCustomView = UIView.fromNib() as? CustomView
. В этом случае скорееT.self
разрешаетсяUIView
, чемCustomView
и не удается найти перо. Я не уверен, почему это - возможно, выводимый тип дляlet
средств, вызываемых как функцияUIView
?попробуйте следующий код.
Редактировать:
источник
Swift 4 расширения протокола
Принятие
Эта реализация предполагает, что Nib имеет то же имя, что и класс UIView. Ex. MyView.xib. Вы можете изменить это поведение, реализовав nibName () в MyView, чтобы возвращать имя, отличное от реализации расширения протокола по умолчанию.
В xib владельцем файла является MyView, а корневым классом представления является MyView.
использование
источник
Я добился этого с помощью Swift с помощью следующего кода:
Не забудьте подключить XIB вида розетку для просмотра выхода , определенного в стриже. Вы также можете настроить First Responder на свое имя класса, чтобы начать подключать любые дополнительные розетки.
Надеюсь это поможет!
источник
Протестировано в Xcode 7 beta 4, Swift 2.0 и iOS9 SDK. Следующий код назначит xib для uiview. Вы можете использовать это пользовательское представление xib в раскадровке и получить доступ к объекту IBOutlet.
Доступ к customview программно
Исходный код - https://github.com/karthikprabhuA/CustomXIBSwift
источник
Если у вас есть много пользовательских представлений в вашем проекте, вы можете создать класс как
UIViewFromNib
Swift 2.3
Swift 3
И в каждом классе просто наследовать от
UIViewFromNib
, вы также можете переопределитьnibName
свойство, если.xib
файл имеет другое имя:источник
Опираясь на вышеуказанные решения.
Это будет работать во всех пакетах проектов и не требует обобщений при вызове fromNib ().
Swift 2
Swift 3
Можно использовать так:
Или вот так:
источник
Swift 4
Не забудьте написать «.first as? CustomView».
Если вы хотите использовать где угодно
Лучшее решение - это ответ Роберта Гаммессона .
Тогда назовите это так:
источник
источник
self
неявно возвращается из всехinit
методов ...Хороший способ сделать это с помощью Swift - использовать enum.
Тогда в вашем коде вы можете просто использовать:
источник
Я предпочитаю это решение (основываясь на ответе, если @ GK100):
В SomeView.swift я загрузил XIB внутри
init
илиinit:frame: CGRect
инициализатора. Нет необходимости присваивать что-либо «себе». Как только XIB загружен, все розетки подключены, включая представление верхнего уровня. Единственное, чего не хватает, это добавить вид сверху в иерархию видов:источник
Swift 3 версия ответа Логана
источник
Вот простой и декларативный способ программной загрузки представления с использованием протокола и расширения протокола (Swift 4.2):
И вы можете использовать это так:
Некоторые дополнительные соображения :
Custom Class
(и выходы / действия, установленные оттуда), а не владелец файла.источник
Я просто делаю так:
В этом примере используется первое представление в наконечнике «MyView.xib» в основном комплекте. Но вы можете изменить либо индекс, имя пера, либо комплект (основной по умолчанию).
Раньше я пробуждал представления в методе view init или создавал общие методы, как в приведенных выше решениях (которые, кстати, умны), но я больше этим не занимаюсь.
Таким образом, я могу использовать разные макеты или характеристики, сохраняя логику и код одного и того же представления.
Мне проще позволить фабричному объекту (обычно viewController, который будет использовать представление) создавать его так, как ему нужно. Иногда вам нужен владелец (обычно, когда созданный вид получает розетку, связанную с создателем), иногда нет ..
Вероятно, поэтому Apple не включила
initFromNib
метод в свой класс UIView ...Чтобы взять пример с уровня земли, вы не знаете, как вы родились. Ты просто родился. Как и мнения;)
источник
Все, что вам нужно сделать, это вызвать метод init в вашем
UIView
классе.Сделайте это так:
Теперь, если вы хотите добавить это представление как вспомогательное представление в контроллере представления, сделайте это так в файле view controller.swift:
источник
Подобно некоторым ответам выше, но более последовательному расширению Swift3 UIView:
Что дает удобство загрузки класса из одноименного nib, но также и из других nibs / bundle.
источник
Вы можете сделать это через раскадровку, просто добавив соответствующие ограничения для просмотра. Вы можете сделать это легко, создав подклассы любого представления, скажем так
BaseView
:Objective-C
Swift 4
Я предоставляю 2 варианта, как добавить ограничения - общий и на языке визуального формата - выберите любой, который вы хотите :)
Также по умолчанию предполагается, что
xib
имя имеет то же имя, что и имя класса реализации. Если нет - просто изменитеxibName
параметр.Если вы делите свое представление на подклассы
BaseView
- вы можете легко поместить любое представление и указать класс в IB.источник
источник
Более мощная версия, основанная на ответе Логана
И вы можете использовать как
источник
Наиболее удобная реализация. Здесь вам нужно два метода, чтобы вернуться непосредственно к объекту вашего класса, а не к UIView.
Пример:
источник
Если вы хотите, чтобы подкласс Swift UIView был полностью автономным и иметь возможность создания экземпляров с помощью init или init (frame :) без раскрытия деталей реализации использования Nib, то вы можете использовать расширение протокола для достижения этого. Это решение позволяет избежать вложенной иерархии UIView, как это предлагается во многих других решениях.
источник
источник
Я предпочитаю ниже расширение
Разница между этим расширением и расширением с лучшим ответом заключается в том, что вам не нужно хранить его константу или переменную.
источник
источник