Могу ли я использовать два xibs с одним диспетчером представлений - re: портирование на iPhone 5
Я только что отправил свое первое приложение в магазин приложений (yay было только что одобрено!). Теперь я хочу обновить его, чтобы работать с (лучше выглядеть) на более крупном экране iPhone 5. Я не намерен ничего менять, кроме как немного изменить макет для большего экрана.
ПРИМЕЧАНИЕ. Я не хочу, чтобы мой текущий xib растягивался.
Возможно ли создать два xib файла (то есть: скопировать мой текущий файл xib для главного экрана) и подключить их обоих к контроллеру представления и сделать так, чтобы при запуске приложения приложение обнаружило, есть ли iPhone 5 или более ранним экраном. Затем, в зависимости от того, какое устройство оно, покажите пользователю другой экран.
Я хочу, чтобы базовое приложение оставалось прежним. Все, что я хочу, это представить немного другой (более высокий) экран для пользователей iPhone 5 с несколькими кнопками/элементами, перемещаемыми для нового макета. Я иначе не буду добавлять или удалять что-либо из интерфейса.
Этот вопрос + вопрос показывает, как переключаться между iPhone или iPad. Итак, этот. Оба являются полезными, но я не знаю, как это изменить для того обстоятельства, когда пользователь использует iPhone 5 с большим экраном или iPhone 4S и ниже. Кроме того, они предполагают два контроллера вида. Мне нужен только один контроллер просмотра, так как абсолютно ничего не происходит в логике контроллера просмотра - меняется только размещение объектов на экране и все это делается в XIB.
Я должен подумать, что ответ должен состоять в том, что контроллер представления iteslf оценивает, какое устройство он работает, а затем представляет соответствующий xib? Да? Нет?
Если да, то как мне это сделать?
Ответы
Ответ 1
[Пересмотрен с полным ответом: 7 октября 2012 г.]
После значительных исследований я нашел ответ, частично на этой странице SO (которая показывает, как определить, какая версия iPhone работает на вашем приложении) и отчасти эта страница SO (показывающая, как иметь два xib, которые имеют один и тот же "Владелец файла" . Последняя часть головоломки (загрузка отдельного xib с помощью метода loadNibNamed:) Я нашел в главе 10 Отличный IOS-программирование в формате Big Nerd Ranch. Вот как:
-
Создайте второй xib (Файл, Новый..., Файл, выберите "Пользовательский интерфейс", выберите "Пусто" и сохраните его. Это создаст новый xib. В приведенном ниже примере мой классический xib (для 3.5 "iPhones) был назван TipMainViewController.xib. Я сохранил новый iPhone 5 xib с именем TipMainViewController-5.xib
-
Сделайте этот новый xib 'File Owner' тем же ViewController, что и ваш существующий xib. Для этого в новом файле xib выберите "Владельцы файлов". Затем в "Identity Inspector" выберите существующий View Controller в качестве пользовательского класса. В моем случае я выбрал "TipMainViewController".
-
Перетащите новый UIView на новый пустой холст xib. В новом инспекторе атрибутов UIView установите атрибут "Размер" на "Retina 4 Full Screen"
-
Выберите все содержимое существующего "Классического" 3.5 "xib", например: все ваши элементы управления, кнопки, селектора, метки и т.д. Скопируйте их и вставьте их в новый iPhone 5 xib. Измените размер/перемещение и т.д. их оптимизировать для iPhone 4 ".
-
Сделайте все подключения к/из File Owner, как и при создании исходного xib.
-
Наконец, в методе 'viewDidLoad' вашего 'single' ViewController вставьте следующую логику (используя, конечно, имена nib/xib):
- (void)loadView
{
[super viewDidLoad];
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
CGSize result = [[UIScreen mainScreen] bounds].size;
if(result.height == 480)
{
// iPhone Classic
[[NSBundle mainBundle] loadNibNamed:@"TipMainViewController" owner:self options:nil];
}
if(result.height == 568)
{
// iPhone 5
[[NSBundle mainBundle] loadNibNamed:@"TipMainViewController-5" owner:self options:nil];
}
}
}
Ответ 2
Вот простой пример рабочего кода для контроллера вашего вида, который показывает, как загрузить myXib-5.xib
на iPhone 5 и myXib.xib
на iPhone/iPod, предшествующих iPhone 5:
- (void)loadView
{
if([[UIScreen mainScreen] bounds].size.height == 568)
{
// iPhone 5
self.view = [[NSBundle mainBundle] loadNibNamed:@"myXib-5" owner:self options:nil][0];
}
else
{
self.view = [[NSBundle mainBundle] loadNibNamed:@"myXib" owner:self options:nil][0];
}
}
Предполагается, что вы ориентируетесь только на iPhone, а не на iPad, чтобы он был простым.
Свойство класса владельца файла XIB также должно быть установлено на контроллер представления, содержащий loadView
.
Ответ 3
Код в ответе был полезен, но мне нужно было что-то, что лучше работало для универсальных приложений (iphone/ipad).
В случае, если кому-то еще нужно то же самое, вот что-то, чтобы вы начали.
Скажем, вы создали универсальное приложение, использующее стандарты именования nib/xib для ios для контроллеров представлений с xib с тем же именем:
Два встроенных значения по умолчанию для автоматической загрузки xib при отсутствии имени передаются initWithNibName:
- ExampleViewController.xib [iphone default, когда nib назван пустым для Retina 3.5 Полный экран для классических макетов iphone 4/4s и т.д....]
- ExampleViewController ~ ipad.xib [ipad/ipad mini default, когда nib named empty]
Теперь скажите, что вам нужны пользовательские xibs для iphone 5/5s в IB, используя опцию Retina 4 Full Screen, т.е. вы не хотите, чтобы 3.5 xib отображались для любых 568h устройств.
Здесь пользовательское соглашение об именах, использующее подход категории:
- ExampleViewController-568h.xib [iphone non default/пользовательское соглашение об именах, когда имя ниба пустое для Retina 4 Full Screen (568h)]
Вместо того, чтобы переопределять встроенные именования по умолчанию, используйте категорию, чтобы помочь установить правильный xib для контроллера.
https://gist.github.com/scottvrosenthal/4945884
ExampleViewController.m
#import "UIViewController+AppCategories.h"
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
nibNameOrNil = [UIViewController nibNamedForDevice:@"ExampleViewController"];
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Do any additional customization
}
return self;
}
UIViewController + AppCategories.h
#import <UIKit/UIKit.h>
@interface UIViewController (AppCategories)
+ (NSString*)nibNamedForDevice:(NSString*)name;
@end
UIViewController + AppCategories.m
// ExampleViewController.xib [iphone default when nib named empty for Retina 3.5 Full Screen]
// ExampleViewController-568h.xib [iphone custom naming convention when nib named empty for Retina 4 Full Screen (568h)]
// ExampleViewController~ipad.xib [ipad/ipad mini default when nib named empty]
#import "UIViewController+AppCategories.h"
@implementation UIViewController (AppCategories)
+ (NSString*)nibNamedForDevice:(NSString*)name
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
if ([UIScreen mainScreen].bounds.size.height == 568)
{
//Check if there a path extension or not
if (name.pathExtension.length) {
name = [name stringByReplacingOccurrencesOfString: [NSString stringWithFormat:@".%@", name.pathExtension] withString: [NSString stringWithFormat:@"-568h.%@", name.pathExtension ]
];
} else {
name = [name stringByAppendingString:@"-568h"];
}
// if 568h nib is found
NSString *nibExists = [[NSBundle mainBundle] pathForResource:name ofType:@"nib"];
if (nibExists) {
return name;
}
}
}
// just default to ios universal app naming convention for xibs
return Nil;
}
@end