Как создать пользовательский класс представления iOS и создать несколько экземпляров его (в IB)?

В настоящее время я создаю приложение, которое будет иметь несколько таймеров, которые в основном все одинаковы.

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

Я создал макет с использованием IB (xcode 4.2), и весь код для таймеров в настоящее время находится только в классе viewcontroller.

У меня с трудом завертывается мой мозг вокруг того, как инкапсулировать все в пользовательский класс, а затем добавить его в viewcontroller, любая помощь будет высоко оценена.

4 Solutions collect form web for “Как создать пользовательский класс представления iOS и создать несколько экземпляров его (в IB)?”

Чтобы ответить концептуально, ваш таймер должен скорее быть подклассом UIView а не UIView .

Чтобы создать экземпляр вашего таймера в IB, просто перетащите UIView его представление контроллера представления и установите его класс для имени класса вашего таймера.

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

Помните, что #import ваш класс таймера в вашем контроллере просмотра.

Изменить: для дизайна IB (для создания экземпляра кода см. Историю изменений)

Я не очень хорошо разбираюсь в раскадровке, но я знаю, что вы можете построить свой интерфейс в IB, используя файл .xib который почти идентичен использованию версии раскадровки; Вы даже сможете копировать и вставлять свои представления в целом из существующего интерфейса в файл .xib .

Чтобы проверить это, я создал новый пустой .xib именем «MyCustomTimerView.xib». Затем я добавил представление, и к нему добавлена ​​метка и две кнопки. Вот так:

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

Я создал новый UIView класса C подкласса UIView именем «MyCustomTimer». В моем .xib я установил класс Owner своего файла MyCustomTimer . Теперь я могу подключать действия и выходы, как и любой другой вид / контроллер. Полученный файл .h выглядит следующим образом:

 @interface MyCustomTimer : UIView @property (strong, nonatomic) IBOutlet UILabel *displayLabel; @property (strong, nonatomic) IBOutlet UIButton *startButton; @property (strong, nonatomic) IBOutlet UIButton *stopButton; - (IBAction)startButtonPush:(id)sender; - (IBAction)stopButtonPush:(id)sender; @end 

Единственное препятствие, которое нужно перепрыгнуть, – это получить этот .xib в моем подклассе UIView . Использование .xib резко сокращает требуемую настройку. И поскольку вы используете раскадровки для загрузки таймеров, которые мы знаем -(id)initWithCoder: это единственный инициализатор, который будет вызываться. Итак, вот как выглядит файл реализации:

 #import "MyCustomTimer.h" @implementation MyCustomTimer @synthesize displayLabel; @synthesize startButton; @synthesize stopButton; -(id)initWithCoder:(NSCoder *)aDecoder{ if ((self = [super initWithCoder:aDecoder])){ [self addSubview: [[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView" owner:self options:nil] objectAtIndex:0]]; } return self; } - (IBAction)startButtonPush:(id)sender { self.displayLabel.backgroundColor = [UIColor greenColor]; } - (IBAction)stopButtonPush:(id)sender { self.displayLabel.backgroundColor = [UIColor redColor]; } @end 

Метод с именем loadNibNamed:owner:options: делает именно то, что звучит так, как будто это так. Он загружает Nib и устанавливает свойство «Владелец файла» для себя. Мы извлекаем первый объект в массиве и являемся корневым представлением Nib. Мы добавляем представление как subview, а Voila – на экран.

Очевидно, это просто меняет цвет фона ярлыка при нажатии кнопок, но этот пример должен хорошо вас направить.

Примечания, основанные на комментариях:

Стоит отметить, что если вы получаете бесконечные проблемы с рекурсией, вы, вероятно, пропустили тонкий трюк этого решения. Это не то, что вы думаете, что это делает. Представление, которое помещается в раскадровку, не видно, но вместо этого загружает другое представление в качестве подвью. Это представление, которое он загружает, представляет собой представление, которое определено в nib. «Владелец файла» в нибе – это невидимое представление. Классная часть состоит в том, что это невидимое представление по-прежнему является классом Objective-C, который может использоваться как контроллер вида для вида, который он вносит из nib. Например, методы IBAction в классе MyCustomTimer – это то, чего вы ожидаете больше в контроллере представления, чем в представлении.

В качестве побочной заметки некоторые могут утверждать, что это нарушает MVC и я согласен с этим. С моей точки зрения, это более тесно связано с пользовательским UITableViewCell , который также иногда должен быть частью контроллера.

Стоит также отметить, что этот ответ должен был дать очень конкретное решение; создайте один наконечник, который может быть создан несколько раз на том же изображении, что и на раскадровке. Например, вы можете легко представить шесть из этих таймеров на экране iPad за один раз. Если вам нужно только указать представление для контроллера вида, который будет использоваться несколько раз в вашем приложении, то решение, предоставленное jyavenard для этого вопроса , почти наверняка станет лучшим решением для вас.

Пример Swift

Обновлено для Swift 3

Вот базовая прогулка. Я многому научился, посмотрев эту серию видео Youtube .

Добавить пользовательские файлы просмотра

Следующие два файла формируют ваш пользовательский вид:

  • .xib-файл для размещения макета
  • .swift как подкласс UIView

Подробности для их добавления приведены ниже.

Файл Xib

Добавьте в проект файл .xib (Файл> Создать> Файл …> Пользовательский интерфейс> Вид). Я вызываю мой ReusableCustomView.xib.

Создайте макет, который требуется для вашего пользовательского представления. В качестве примера я сделаю макет с UILabel и UIButton . Рекомендуется использовать автоматическую компоновку, чтобы вещи автоматически изменялись независимо от того, какой размер вы задали позже.

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

Быстрый файл

Добавьте в проект файл .swift (Файл> Создать> Файл …> Источник> Файл Swift). Это подкласс UIView и я UIView ReusableCustomView.swift.

 import UIKit class ResuableCustomView: UIView { } 

Сделать файл Swift владельцем

Вернитесь в ваш .xib-файл и нажмите «Владелец файла» в структуре документа. В Identity Inspector напишите имя вашего swift-файла как имя пользовательского класса.

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

Добавить пользовательский код просмотра

Замените содержимое файла ReusableCustomView.swift следующим кодом:

 import UIKit class ResuableCustomView: UIView { @IBOutlet var view: UIView! @IBOutlet weak var label: UILabel! @IBAction func buttonTap(_ sender: UIButton) { label.text = "Hi" } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) Bundle.main.loadNibNamed("ReusableCustomView", owner: self, options: nil) self.addSubview(view) view.frame = self.bounds } } 

Обязательно получите правописание для имени вашего .xib-файла.

Подключить выходные и действия

Подключите выходы и действия с помощью (1) перетаскивания элемента управления из макета xib в быстрый код пользовательского представления или (2) щелчок правой кнопкой мыши по контуру документа и перетаскивание кнопки «плюс» до «Владелец файла». Способ 2 проиллюстрирован ниже.

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

Использование пользовательского вида

Теперь ваш пользовательский вид завершен. Все, что вам нужно сделать, это добавить UIView везде, где вы хотите, в свою основную раскадровку. Задайте имя класса вида ReusableCustomView в Identity Inspector.

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

На момент написания этой статьи у меня возникли проблемы с добавлением @IBDesignable к коду, поэтому представления не отображаются в IB, но они выполняются при запуске приложения.

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

Ответ для контроллеров представлений, а не просмотров :

Существует более простой способ загрузить xib из раскадровки. Скажем, ваш контроллер имеет тип MyClassController, который наследуется от UIViewController .

Вы добавляете UIViewController используя IB в своем раскадровке; измените тип класса на MyClassController. Удалите представление, которое было автоматически добавлено в раскадровку.

Убедитесь, что XIB, который вы хотите вызвать, называется MyClassController.xib.

Когда класс будет создан при загрузке раскадровки, xib будет автоматически загружен. Причина этого связана с реализацией по умолчанию UIViewController которая вызывает XIB с именем класса.

На самом деле это не ответ, но я считаю полезным поделиться этим подходом.

Objective-C

  1. Импортируйте CustomViewWithXib.h и CustomViewWithXib.m в свой проект
  2. Создайте пользовательские файлы с тем же именем (.h / .m / .xib)
  3. Наследовать свой пользовательский класс из CustomViewWithXib

стриж

  1. Импортируйте CustomViewWithXib.swift в свой проект
  2. Создайте пользовательские файлы с тем же именем (.swift и .xib)
  3. Наследовать свой пользовательский класс из CustomViewWithXib

Необязательный :

  1. Перейдите в свой xib-файл, задайте владельцу имя вашего собственного класса, если вам нужно подключить некоторые элементы (более подробную информацию см. В разделе «Сделать файл Swift владельцем ответа @Suragch»)

Это все, теперь вы можете добавить свой собственный вид в свою раскадровку, и это будет показано 🙂

CustomViewWithXib.h :

  #import <UIKit/UIKit.h> /** * All classes inherit from CustomViewWithXib should have the same xib file name and class name (.h and .m) MyCustomView.h MyCustomView.m MyCustomView.xib */ // This allows seeing how your custom views will appear without building and running your app after each change. IB_DESIGNABLE @interface CustomViewWithXib : UIView @end 

CustomViewWithXib.m :

 #import "CustomViewWithXib.h" @implementation CustomViewWithXib #pragma mark - init methods - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { // load view frame XIB [self commonSetup]; } return self; } - (instancetype)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; if (self) { // load view frame XIB [self commonSetup]; } return self; } #pragma mark - setup view - (UIView *)loadViewFromNib { NSBundle *bundle = [NSBundle bundleForClass:[self class]]; // An exception will be thrown if the xib file with this class name not found, UIView *view = [[bundle loadNibNamed:NSStringFromClass([self class]) owner:self options:nil] firstObject]; return view; } - (void)commonSetup { UIView *nibView = [self loadViewFromNib]; nibView.frame = self.bounds; // the autoresizingMask will be converted to constraints, the frame will match the parent view frame nibView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; // Adding nibView on the top of our view [self addSubview:nibView]; } @end 

CustomViewWithXib.swift :

 import UIKit @IBDesignable class CustomViewWithXib: UIView { // MARK: init methods required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) commonSetup() } override init(frame: CGRect) { super.init(frame: frame) commonSetup() } // MARK: setup view private func loadViewFromNib() -> UIView { let viewBundle = NSBundle(forClass: self.dynamicType) // An exception will be thrown if the xib file with this class name not found, let view = viewBundle.loadNibNamed(String(self.dynamicType), owner: self, options: nil)[0] return view as! UIView } private func commonSetup() { let nibView = loadViewFromNib() nibView.frame = bounds // the autoresizingMask will be converted to constraints, the frame will match the parent view frame nibView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] // Adding nibView on the top of our view addSubview(nibView) } } 

Здесь вы можете найти несколько примеров.

Надеюсь, это поможет.

  • UIDocumentInteractionController и файл из Интернета
  • Как создать пользовательский UIAlertView в приложении iphone
  • Не удалось запустить процесс: не удалось выполнить задачу для процесса 2847
  • Поддержка iOS 3.2 (или 4.0) с XCode 4.5
  • Использование SDK iOS 7 с llvm-gcc-4.2
  • Приложение застряло в заставке на iOS 9 без ошибок
  • инструменты fastlane и xcode8, должен ли я использовать его?
  • Xcode не обнаружит устройство iPhone 5 с iOS 6.1.4
  • iOS: динамическая структура, основанная на зависимости статической библиотеки
  • Как удалить файлы каталога tmp приложения ios?
  • Сохранить значение datePicker с помощью NSUserdefaults (xcode, swift2)
  • Interesting Posts

    После обновления до iOS 9 мое устройство не поддерживается Xcode 6.4

    Swift IOS: как выполнить запрос REST POST

    Почему в iOS нет AUNetSend? (Или любые альтернативные предложения)

    Попытка отладить тайну синусоиды с помощью AKMIDISampler в Audiokit

    Сроки с быстрым классом с динамической переменной, которая наследуется от цели c, где методы get / set заменяются

    UITextField запускает нежелательный сеанс, когда клавиатура отклоняется

    Исправлена ​​ошибка с полной прокруткой боковой панели на iOS

    Как получить раму вида внутри другого вида?

    Как создать веревку в SpriteKit?

    IAP Auto Renewable Обновление подписки на обновление до истечения срока действия

    EXC_BAD_ACCESS в простом коде в выпуске

    Метод делегата StoreKit не вызван

    iOS автоматически отменит диалог идентификации TouchID

    В CBPeripheralManager, как узнать, нажимает ли пользователь кнопку отмены при попытке сопряжения

    XCODE 7.1 Swift 2 Неизвестный класс в файле Interface Builder

    PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.