Повторное использование uibview xib в раскадровке

Обычно я люблю создавать и проектировать свои интерфейсы в конструкторе интерфейсов. Иногда мне нужно создать одно представление в xib, которое можно повторно использовать в нескольких контроллерах представления в раскадровке.

5 ответов

Решение

Повторное использование и рендеринг xib в раскадровке.

Протестировано с Swift 2.2 и Xcode 7.3.1

1 ---- Создайте новый UIView с именем 'DesignableXibView'

  • Файл> Создать> Файл> Источник> Какао Touch Class> UIView

2 ---- Создайте соответствующий xib-файл с именем "DesignableXibView"

  • Файл> Создать> Файл> Интерфейс пользователя> Вид

3 ---- Установите владельца файла из xib

  1. выберите XIB
  2. выберите владельца файла
  3. установите пользовательский класс на "DesignableXibView" в Identity Inspector.

Установка владельца Xib в пользовательский класс

  • Примечание: не устанавливайте пользовательский класс представления на 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 ---- Проверьте свой повторно используемый вид в раскадровке

  1. Откройте раскадровку
  2. Добавить вид
  3. Установите пользовательский класс этого представления
  4. подождите секунду... БУМ!!

Рендеринг Xib внутри контроллера раскадровки

NEW! обновленный ответ с возможностью рендеринга прямо в раскадровке (и быстро!)

Работает в Xcode 6.3.1

Создайте новый UIView с именем "ReuseableView"

  • Файл> Создать> Файл> Источник> Какао Touch Class > UIView

Создайте соответствующий файл XIB с именем "ReuseableView"

  • Файл> Создать> Файл> Интерфейс пользователя> Вид

Установить владельца файла из xib

  1. выберите XIB
  2. выберите владельца файла
  3. установите пользовательский класс на "ReusableView" в Identity Inspector. введите описание изображения здесь

    • Примечание: не устанавливайте пользовательский класс представления на XIB. Только владелец файла!

Сделайте вывод из представления в ReuseableView.xib к вашему интерфейсу ReuseableView.h

  1. Open Assistant Editor
  2. 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;
}

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

Проверьте свой повторно используемый вид в раскадровке

  1. Откройте раскадровку
  2. Добавить вид
  3. Установите пользовательский класс этого представления

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

Беги и наблюдай! введите описание изображения здесь

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 особым образом или добавлять экземпляр своего пользовательского представления в качестве своего собственного подпредставления.

Просто сделай это:

  1. Импортировать фреймворк BFWControls
  2. Измените свой суперкласс с 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);
        }
    }
Другие вопросы по тегам