Зазвичай я люблю створювати та розробляти свої інтерфейси в інтерфейсі конструктора. Іноді мені потрібно створити єдине представлення в xib, яке можна використовувати повторно в декількох контролерах подання в раскадровці.
Зазвичай я люблю створювати та розробляти свої інтерфейси в інтерфейсі конструктора. Іноді мені потрібно створити єдине представлення в xib, яке можна використовувати повторно в декількох контролерах подання в раскадровці.
Відповіді:
Перевірено за допомогою Swift 2.2 та Xcode 7.3.1
// 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
}
}
НОВЕ! оновлена відповідь з можливістю візуалізації безпосередньо в раскадровці (і швидко!)
Працює в Xcode 6.3.1
Створіть новий UIView з назвою 'ReuseableView'
Створіть відповідний файл xib з назвою 'ReuseableView'
Встановіть власника файлу xib
встановіть для власного класу значення «ReusableView» в інспекторі посвідчень.
Зробіть розетку з подання в ReuseableView.xib на ваш інтерфейс ReuseableView.h
Додайте реалізацію 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;
}
Перевірте свій багаторазовий вигляд у розкадруванні
Біжи і спостерігай!
UINib(nibName: nibName, bundle: nil).instantiateWithOwner(nil, options: nil)
швидше, ніж версія NSBundle.
@IBDesignable on the class.
вам також потрібно реалізувати init(frame:)
- але крім того, це працює досить добре! supereasyapps.com/blog/2014/12/15 / ...
Swift 3 і 4 Оновіть прийняту відповідь
1. Створіть новий UIView з назвою 'DesignableXibView'
2. Створіть відповідний файл xib з назвою 'DesignableXibView'
3. Встановіть власника файлу xib
Виберіть "DesignableXibView.xib"> "Власник файлу"> встановіть для "Custom Class" значення "DesignableXibView" в інспекторі посвідчень.
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
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 Перевірте свій багаторазовий вигляд у розкадруванні
Відкрийте свою раскадровку
Додайте подання
Встановіть спеціальний клас цього подання
DesignableXibView
. Створіть проект, щоб переглянути зміни.
String(describing: type(of: self))
слід робити це безпечно
Функція 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]))
}
Простого перетворення Swift
на Objective-C
недостатньо для того, щоб це працювало. Мені було важко дозволити живий рендеринг в Storyboard.
Після перекладу цілого коду подання добре завантажується під час роботи на пристрої (або симуляторі), але рендеринг в реальному часі в Storyboard не працює. Причиною цього є те, що я використовував, [NSBundle mainBundle]
тоді як Interface Builder не має доступу до mainBundle. Натомість вам доведеться використовувати [NSBundle bundleForClass:self.classForCoder]
. БУМ, прямий рендеринг працює зараз!
Примітка: якщо у вас виникли проблеми з автоматичним Safe Area Layout Guides
макетом , спробуйте відключити в Xib.
Для вашої зручності я залишаю тут весь свій код, щоб вам просто потрібно було скопіювати / вставити (для всього процесу слідкуйте за оригінальною відповіддю ):
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
Скажіть, якщо ви стикаєтесь із деякими проблемами, але це мало не зразу вийти :)
Якщо комусь цікаво, ось версія 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);
}
}
Ось відповідь, яку ви весь час хотіли. Ви можете просто створити свій CustomView
клас, створити його головний екземпляр у xib з усіма підпроглядами та торговими точками. Тоді ви можете застосувати цей клас до будь-яких екземплярів на ваших раскадровках або інших xibs.
Не потрібно возитися з власником файлу, підключати розетки до проксі-сервера, модифікувати xib особливим чином або додавати екземпляр власного подання як підпрогляд самого себе.
Просто зробіть це:
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
Том 👣