Повторное использование uibview xib в раскадровке
Обычно я люблю создавать и проектировать свои интерфейсы в конструкторе интерфейсов. Иногда мне нужно создать одно представление в xib, которое можно повторно использовать в нескольких контроллерах представления в раскадровке.
5 ответов
Повторное использование и рендеринг xib в раскадровке.
Протестировано с Swift 2.2 и Xcode 7.3.1
1 ---- Создайте новый UIView с именем 'DesignableXibView'
- Файл> Создать> Файл> Источник> Какао Touch Class> UIView
2 ---- Создайте соответствующий xib-файл с именем "DesignableXibView"
- Файл> Создать> Файл> Интерфейс пользователя> Вид
3 ---- Установите владельца файла из xib
- выберите XIB
- выберите владельца файла
- установите пользовательский класс на "DesignableXibView" в Identity Inspector.
- Примечание: не устанавливайте пользовательский класс представления на XIB. Только владелец файла!
4 ---- Реализация DesignableXibView
// DesignableXibView.swift
import UIKit
@IBDesignable
class DesignableXibView: UIView {
var contentView : UIView?
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
contentView = loadViewFromNib()
// use bounds not frame or it'll be offset
contentView!.frame = bounds
// Make the view stretch with containing view
contentView!.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(contentView!)
}
func loadViewFromNib() -> UIView! {
let bundle = NSBundle(forClass: self.dynamicType)
let nib = UINib(nibName: String(self.dynamicType), bundle: bundle)
let view = nib.instantiateWithOwner(self, options: nil)[0] as! UIView
return view
}
}
5 ---- Проверьте свой повторно используемый вид в раскадровке
- Откройте раскадровку
- Добавить вид
- Установите пользовательский класс этого представления
- подождите секунду... БУМ!!
NEW! обновленный ответ с возможностью рендеринга прямо в раскадровке (и быстро!)
Работает в Xcode 6.3.1
Создайте новый UIView с именем "ReuseableView"
- Файл> Создать> Файл> Источник> Какао Touch Class > UIView
Создайте соответствующий файл XIB с именем "ReuseableView"
- Файл> Создать> Файл> Интерфейс пользователя> Вид
Установить владельца файла из xib
- выберите XIB
- выберите владельца файла
установите пользовательский класс на "ReusableView" в Identity Inspector.
- Примечание: не устанавливайте пользовательский класс представления на XIB. Только владелец файла!
Сделайте вывод из представления в ReuseableView.xib к вашему интерфейсу ReuseableView.h
- Open Assistant Editor
- Ctrl + Перетащите из вида в ваш интерфейс
Добавьте реализацию initWithCoder для загрузки представления и добавьте в качестве подпредставления.
- (id)initWithCoder:(NSCoder *)aDecoder{
self = [super initWithCoder:aDecoder];
if (self) {
// 1. load the interface
[[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
// 2. add as subview
[self addSubview:self.view];
// 3. allow for autolayout
self.view.translatesAutoresizingMaskIntoConstraints = NO;
// 4. add constraints to span entire view
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[view]|" options:0 metrics:nil views:@{@"view":self.view}]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[view]|" options:0 metrics:nil views:@{@"view":self.view}]];
}
return self;
}
Проверьте свой повторно используемый вид в раскадровке
- Откройте раскадровку
- Добавить вид
- Установите пользовательский класс этого представления
Беги и наблюдай!
Swift 3&4 Обновление до принятого ответа
1. Создайте новый UIView с именем "DesignableXibView"
- Файл> Создать> Файл> Источник> Какао Touch Class> UIView
2. Создайте соответствующий файл XIB с именем "DesignableXibView"
- Файл> Создать> Файл> Интерфейс пользователя> Вид
3. Установите владельца файла XIB
Выберите "DesignableXibView.xib"> "Владелец файла"> установите для "Пользовательского класса" значение "DesignableXibView" в Инспекторе удостоверений.
- Примечание: не устанавливайте пользовательский класс представления на XIB. Только владелец файла!
4. Реализация DesignableXibView
import UIKit
@IBDesignable
class DesignableXibView: UIView {
var contentView : UIView!
override init(frame: CGRect) {
super.init(frame: frame)
xibSetup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
xibSetup()
}
func xibSetup() {
contentView = loadViewFromNib()
// use bounds not frame or it'll be offset
contentView.frame = bounds
// Make the view stretch with containing view
contentView.autoresizingMask = [UIViewAutoresizing.flexibleWidth, UIViewAutoresizing.flexibleHeight]
// Adding custom subview on top of our view (over any custom drawing > see note below)
addSubview(contentView)
}
func loadViewFromNib() -> UIView! {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
let view = nib.instantiate(withOwner: self, options: nil).first as! UIView
return view
}
}
5 Проверьте свой повторно используемый вид в раскадровке
Откройте раскадровку
Добавить вид
Установите пользовательский класс этого представления
Функция initWithCoder в swift 2, если у кого-то есть проблемы с переводом:
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
UINib(nibName: String(self.dynamicType), bundle: NSBundle.mainBundle()).instantiateWithOwner(self, options: nil)
self.addSubview(view)
self.view.translatesAutoresizingMaskIntoConstraints = false
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterY , metrics: nil, views: ["view": self.view]))
self.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|", options: NSLayoutFormatOptions.AlignAllCenterX , metrics: nil, views: ["view": self.view]))
}
Для всех, кто пытается адаптировать принятый ответ (@Garfbargle) к Objective-C
Просто конвертировать Swift
в Objective-C
недостаточно, чтобы заставить это работать. Мне было трудно разрешить живую визуализацию в раскадровке.
После перевода всего кода представление хорошо загружается при запуске на устройстве (или в симуляторе), но рендеринг в реальном времени в раскадровке не работает. Причина в том, что я использовал [NSBundle mainBundle]
тогда как Интерфейсный Разработчик не имеет доступа к mainBundle. Вместо этого вы должны использовать [NSBundle bundleForClass:self.classForCoder]
, БУМ, живая рендеринг работает сейчас!
Примечание: если у вас есть проблемы с автоматическим расположением, попробуйте отключить Safe Area Layout Guides
в сиб.
Для вашего удобства я оставляю весь свой код здесь, так что вам просто нужно скопировать / вставить (для всего процесса следуйте оригинальному ответу):
BottomBarView.h
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface BottomBarView : UIView
@end
BottomBarView.m
#import "BottomBarView.h"
@interface BottomBarView() {
UIView *contentView;
}
@end
@implementation BottomBarView
-(id) initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self xibSetup];
}
return self;
}
-(id) initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self xibSetup];
}
return self;
}
-(void) xibSetup {
contentView = [self loadViewFromNib];
contentView.frame = self.bounds;
contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self addSubview:contentView];
}
-(UIView*) loadViewFromNib {
NSBundle *bundle = [NSBundle bundleForClass:self.classForCoder]; //this is the important line for view to render in IB
UINib *nib = [UINib nibWithNibName:NSStringFromClass([self class]) bundle:bundle];
UIView *view = [nib instantiateWithOwner:self options:nil][0];
return view;
}
@end
Скажите, если у вас возникли какие-то проблемы, но это должно работать почти из коробки:)
Вот ответ, который вы хотели все время. Вы можете просто создать свой CustomView
класс, иметь главный экземпляр этого в xib со всеми подпредставлениями и выходами. Затем вы можете применить этот класс к любым экземплярам в ваших раскадровках или других Xibs.
Не нужно возиться с владельцем файла, подключать розетки к прокси-серверу, модифицировать XIB особым образом или добавлять экземпляр своего пользовательского представления в качестве своего собственного подпредставления.
Просто сделай это:
- Импортировать фреймворк BFWControls
- Измените свой суперкласс с
UIView
вNibView
(или изUITableViewCell
вNibTableViewCell
)
Это оно!
Он даже работает с IBDesignable для визуализации вашего пользовательского представления (включая подпредставления из xib) во время разработки в раскадровке.
Вы можете прочитать больше об этом здесь: https://medium.com/build-an-app-like-lego/embed-a-xib-in-a-storyboard-953edf274155
И вы можете получить среду BFWControls с открытым исходным кодом здесь: https://github.com/BareFeetWare/BFWControls
Том
Если кому-то интересно, вот версия кода Xamarin.iOS. Шаг 4 из @Garfbargle
public partial class CustomView : UIView
{
public ErrorView(IntPtr handle) : base(handle)
{
}
[Export("awakeFromNib")]
public override void AwakeFromNib()
{
var nibObjects = NSBundle.MainBundle.LoadNib("CustomView", this, null);
var view = (UIView)Runtime.GetNSObject(nibObjects.ValueAt(0));
view.Frame = Bounds;
view.AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight;
AddSubview(rootView);
}
}