Наскільки я можу зрозуміти, іноді дійсно потрібно підклас UinavigationBar виконати якийсь нестандартний рестайлінг. Іноді можна уникнути необхідності робити це за допомогою категорій , але не завжди.
На даний момент, наскільки мені відомо, єдиний спосіб встановити користувацький UINavigationBar в UIViewController - це через IB (тобто через архів) - це, мабуть, не повинно бути таким чином, але наразі ми повинні жити з цим.
Це часто нормально, але іноді використання IB насправді неможливо.
Отже, я побачив три варіанти:
- Підклас UINavigationBar і підключіть все це до IB, а потім роздумуйте про завантаження перо кожного разу, коли я хочу UINavigationController,
- Використовуйте заміну методу в категорії, щоб змінити поведінку UINavigationBar, а не підкласифікацію, або
- Підклас UINavigationBar та трохи поглинайте архівування / деархівування UINavigationController.
Варіант 1 у цьому випадку був для мене нездійсненним (або, принаймні, надто надокучливим), оскільки мені потрібно було програмно створити UINavigationController, 2, на мій погляд, є трохи небезпечним і більш крайнім варіантом, тому я обрав варіант 3.
Мій підхід полягав у створенні "шаблону" архіву UINavigationController та його архівуванні, повертаючи його в initWithRootViewController
.
Ось як:
У IB я створив UINavigationController з відповідним класом, встановленим для UINavigationBar.
Потім я взяв існуючий контролер і зберіг заархівовану копію його за допомогою +[NSKeyedArchiver archiveRootObject:toFile:]
. Я щойно зробив це в рамках делегата програми, в симуляторі.
Потім я використав утиліту 'xxd' з прапором -i, щоб згенерувати c-код із збереженого файлу, щоб вставити заархівовану версію в мій підклас ( xxd -i path/to/file
).
Усередині initWithRootViewController
я розархівую цей шаблон і встановлюю себе як результат розпакування:
// This is the data from [NSKeyedArchiver archivedDataWithRootObject:controller], where
// controller is a CTNavigationController with navigation bar class set to CTNavigationBar,
// from IB. This c code was created using 'xxd -i'
static unsigned char archived_controller[] = {
0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd4, 0x01, 0x02, 0x03,
...
};
static unsigned int archived_controller_len = 682;
...
- (id)initWithRootViewController:(UIViewController *)rootViewController {
// Replace with unarchived view controller, necessary for the custom navigation bar
[self release];
self = (CTNavigationController*)[NSKeyedUnarchiver unarchiveObjectWithData:[NSData dataWithBytes:archived_controller length:archived_controller_len]];
[self setViewControllers:[NSArray arrayWithObject:rootViewController]];
return [self retain];
}
Тоді я можу просто захопити новий екземпляр мого підкласу UIViewController, у якому встановлена спеціальна панель навігації:
UIViewController *modalViewController = [[[CTNavigationController alloc] initWithRootViewController:myTableViewController] autorelease];
[self.navigationController presentModalViewController:modalViewController animated:YES];
Це дає мені модальний UITableViewController із налаштованою панеллю навігації та панеллю інструментів, а також із спеціальним класом панелі навігації. Мені не потрібно було робити будь-який злегка неприємний метод заміни, і мені не доводиться базікати перо, коли я справді просто хочу працювати програмно.
Я хотів би бачити еквівалент +layerClass
усередині UINavigationController - +navigationBarClass
- але наразі це працює.