Использование объекта xib внутри другого xib

Я разрабатываю с помощью IB конкретную кнопку (с некоторыми ярлыками, и с ImageView и т.д.).

Я бы хотел использовать этот объект xib (кнопка) в другом xib, где у меня есть 6 объектов этой кнопки.

Я знаю, что могу сделать это программно, используя идентификатор класса, но тогда я должен поместить свои таблицы и изображения, а также установить значения по умолчанию и все остальное в коде.

Мне интересно, можно ли делать то же самое, используя только IB? (конечно, я бы все равно установил значения в коде, но я хочу, чтобы позиции lables/imageView и все остальные были установлены в xib)

Спасибо

Edit

Итак, я понимаю, что я просил сначала, невозможно. Теперь я пытаюсь сделать следующее:

Я создал ButtonTest.xib. Внутри Xib у меня есть UIView и 3 subviews (2 таблицы и кнопка). В инспекторе я установил класс UIView ButtonTest. Внутри ButtonTest.m У меня есть 3 выхода для каждого из подзонов, которые я подключаю в IB.

Далее у меня есть ButtonTestViewController.xib. Внутри я положил один вид и установил его в инспекторе как ButtonTest. Я подключаю этот вид к выходу myTextView внутри ButtonTestViewController.m класса ButtonTest

Теперь это код внутри ButtonTestViewController.m viewDidLoad:

- (void)viewDidLoad {
    [super viewDidLoad];

    NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:@"ButtonTest" owner:nil options:nil];
    ButtonTest *mainView = (ButtonTest*)[subviewArray objectAtIndex:0];

    self.myTextView = mainView;
}

То, что я надеялся, будет состоять в том, что представление в ButtonTestViewController.xib станет представлением, которое я создал в ButtonTest.xib. Этого просто не происходит. происходит то, что вид внутри ButtonTestViewController.xib остается прежним.

Стоит отметить, что если я добавлю:

[self.view addSubview:mainView];

Он добавляет новый вид, помимо существующего.

Любая идея, как сделать то, что я хочу?

В конце концов я хотел бы иметь 6 представлений в ButtonTestViewController.xib, все будут выглядеть как шаблон ButtonTest.xib, а значения lables будут установлены в коде.

Edit2

Хорошо, ребята, я сделал все, что вы сказали, и это сработало как шарм. Единственная проблема, с которой я столкнулся сейчас, заключается в том, что представление в ButtonTestViewController.xib немного больше, чем представление в ButtonTest.xib. Когда это произойдет, маска на кнопке выглядит чрезвычайно размытой. Когда они имеют одинаковый размер, все это хорошо.

@Ned - я использовал точный код, который вы разместили в моем методе InitWithCoder, за исключением того, что я переключил предложение фрейма на это:

self.bounds = mainView.frame;

Я пробовал играть в режиме контента в IB, пытаясь исправить его, но безрезультатно.

Когда я использую его, как вы разместили, что означает:

mainView.frame = self.bounds;

Он не работает вообще, и размеры обоих представлений остаются неизменными. Здесь я попытался сыграть с resizeMask, но все равно не работал.

И идея, как исправить эти 2 проблемы? Спасибо, ребята!

Изменить 3

Мне удалось исправить одну из проблем, изменив размер представления ButtonTestViewController.xib на ButtonTest.xib. Это то, что я сделал (используя код для устранения размытой проблемы, взятой из здесь)

self.bounds = CGRectMake(0, 0, mainView.frame.size.width, mainView.frame.size.height);
        CGRect overlay2Frame = self.frame;
        overlay2Frame.origin.x = round(overlay2Frame.origin.x);
        overlay2Frame.origin.y = round(overlay2Frame.origin.y);
        self.frame = overlay2Frame;

Другая проблема, которую я до сих пор не могу решить. представление в ButtonTest.xib просто не станет больше, чтобы соответствовать другому представлению.

Ответы

Ответ 1

Вы можете сделать это и довольно легко. То, как я это делаю, это создать подкласс UIView (пусть он называется "MyView.m" и "MyView.h" ), а затем нить под названием "MyView.xib".

Сначала в консоли выберите File Owner и установите класс в "MyView". Это приведет к тому, что IBOutlets/Actions из вашего класса появятся в IB. Добавьте общий вид верхнего уровня (если он уже не имеет его уже) в качестве основного представления и добавьте другие пользовательские элементы (UILabels и UIImageViews) в качестве подзонов основного UIView.

Затем добавьте следующий код, чтобы он вызывался при инициализации MyView (помните, что если вы инициализируете из nib, вы получите доступ к - (id) initWithCoder: (NSCoder *) aDecoder).

NSArray *subviewArray = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass([self class]) owner:self options:nil];
UIView *mainView = [subviewArray objectAtIndex:0];

//Just in case the size is different (you may or may not want this)
mainView.frame = self.bounds;

[self addSubview:mainView];

То, что это делает, загружает иерархию представлений из вашего nib в NSArray, и поскольку у вас только один UIView верхнего уровня, вы просто добавляете это как подзаголовок своего пользовательского UIView.

Это позволяет вам создавать UIViews (и другие подклассы UIView) в Interface Builder.

EDIT: обновлено до редактирования OP.

Как я всегда это делал, сначала следуя моим указаниям выше. Одно отличие состоит в том, что в вашем ButtonTest nib вы меняете класс UIView на ButtonTest, но я меняю класс File Owner на ButtonTest. Затем внутри ButtonTest.m введите loadNibNamed. Теперь, чтобы добавить этот объект в ButtonTestViewController.xib, добавьте UIView (или UIButton, любой элемент ButtonTest подклассифицирован) и измените класс на ButtonTest.

Это немного запутанно, поэтому я попытаюсь разбить его на файл.

ButtonTestViewController.xib: добавьте UIButton (от любого наследуемого ButtonTest) и измените класс на ButtonTest

ButtonTest.m: Внутри метода "initWithCoder" сделайте все содержимое "loadNibNamed", которое у меня выше

ButtonTest.xib: измените класс владельца файла на ButtonTest и соедините все IBOutlets и IBActions

Ответ 2

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

Цикл существует, если корневой вид в вашем XIB имеет "Пользовательский класс", установленный в MyView. Это вызывает ситуацию, когда представление, загруженное из XIB, снова вызывает инициализатор MyView и, следовательно, создает бесконечный цикл. Решение состоит в том, что "Пользовательский класс" должен быть UIView, и только класс File Owner должен быть установлен в MyView (чтобы иметь возможность назначать IBOutlets и IBActions).

Ответ 3

Swift 3.0

создать быстрый файл с классом

class ViewXIBfileClassView: UIView {
.....
}

создать Xib файл с представлением: ViewXIBfileClassView

создать класс представления оболочки

class ViewWrapper: UIView {

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        let view = UINib(nibName: "ViewXIBfileClassView_file", bundle: nil).instantiate(withOwner: nil, options: nil)[0] as! viewXIBfileClassView
        self.addSubview(view)
        view.bindEdgesToSuperview()
    }
}

добавить расширение в UIView

extension UIView {
    /// Adds constraints to the superview so that this view has same size and position.
    /// Note: This fails the build if the `superview` is `nil` – add it as a subview before calling this.
    func bindEdgesToSuperview() {
        guard let superview = superview else {
            preconditionFailure("`superview` was nil – call `addSubview(view: UIView)` before calling `bindEdgesToSuperview()` to fix this.")
        }
        translatesAutoresizingMaskIntoConstraints = false
        ["H:|-0-[subview]-0-|", "V:|-0-[subview]-0-|"].forEach { visualFormat in
            superview.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: visualFormat, options: .directionLeadingToTrailing, metrics: nil, views: ["subview": self]))
        }
    }
}

Используйте UIView с ViewWrapper внутри всех Xib файлов, которые вы хотите

Ответ 4

Если ваш класс является подклассом UIButton, например, вы можете открыть библиотеку в построителе интерфейсов, и она будет находиться под вкладкой "классы" при ее поиске, и вы можете перетащить ее.

Вы также можете просто перетащить UIButton и установить его класс в панели инспектора.

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