Пользовательский интерфейс UINavigationBar

Я пытаюсь настроить собственный фон для всего моего навигационного блока (а не только titleView), но борется.

Я нашел эту ветку

http://discussions.apple.com/thread.jspa?threadID=1649012&tstart=0

Но я не уверен, как реализовать приведенный fragment кода. Является ли код реализованным как новый class? Также, где я устанавливаю UINavigationController поскольку у меня есть приложение, созданное с помощью шаблона NavigationView, поэтому оно не выполняется в моем корневом controllerе в соответствии с примером

Вам просто нужно перегрузить drawRect следующим образом:

 @implementation UINavigationBar (CustomImage) - (void)drawRect:(CGRect)rect { UIImage *image = [UIImage imageNamed: @"NavigationBar.png"]; [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } @end 

Уддхав и лефлай правы. Этот код работает хорошо:

 @interface CustomNavigationBar : UINavigationBar @end @implementation CustomNavigationBar -(void) drawRect:(CGRect)rect { UIImage *image = [UIImage imageNamed: @"myNavBarImage"]; [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } @end // this can go anywhere +(UINavigationController*) myCustomNavigationController { MyViewController *vc = [[[MyViewController alloc] init] autorelease]; UINavigationController *nav = [[[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil] objectAtIndex:0]; nav.viewControllers = [NSArray arrayWithObject:vc]; return nav; } 

Вы должны создать CustomNavigationController.xib и поместить в него UINavigationController и изменить class navigationBar на «CustomNavigationBar».

Вы должны использовать прокси-сервер «внешний вид» для изменения фона и других свойств стиля элементов управления, таких как UINavigationBar , UIToolBar и т. Д. В iOS 5.xx. Тем не менее, они недоступны для iOS 4.xx, поэтому для обратной совместимости вам требуется гибридное решение.

Если вы хотите поддерживать как iOS 4.xx, так и iOS 5.xx (т. Е. Ваш DeploymentTarget равен 4.xx), вы должны быть осторожны в том, чтобы обернуть вызов прокси-серверу внешнего вида, проверив во время выполнения, если присутствует селектор «появления» или нет.

Вы можете сделать это:

 //Customize the look of the UINavBar for iOS5 devices if ([[UINavigationBar class]respondsToSelector:@selector(appearance)]) { [[UINavigationBar appearance] setBackgroundImage:[UIImage imageNamed:@"NavigationBar.png"] forBarMetrics:UIBarMetricsDefault]; } 

Вы также должны оставить обходное решение iOS 4.xx, которое вы, возможно, внедрили. Если вы drawRect обходное решение drawRect для устройств iOS 4.xx, как упоминалось в @ludwigschubert, вы должны оставить это в:

 @implementation UINavigationBar (BackgroundImage) //This overridden implementation will patch up the NavBar with a custom Image instead of the title - (void)drawRect:(CGRect)rect { UIImage *image = [UIImage imageNamed: @"NavigationBar.png"]; [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; } @end 

Это заставит NavBar выглядеть одинаково как на устройствах iOS 4, так и на iOS 5.

Внедрение категории нецелесообразно. iOS5 может помочь в решении этой проблемы. Но для старых API-интерфейсов вы можете –

  1. Подclass UINavigationBar чтобы сказать CustomNavBar и реализовать пользовательский drawRect из ответа Лития.
  2. Для всех UINavigationControllers , основанных на IB, предоставить CustomNavBar как пользовательский class для своего UINavigationBar .
  3. Для всех UINavigationControllers основе кода. Создайте XIB с помощью UINavigationController и сделайте второй шаг. Затем укажите заводский метод в коде, который загружает UINavigationController из nib и предоставляет IBOutlet .

Например.

 [[NSBundle mainBundle] loadNibNamed:@"CustomNavigationController" owner:self options:nil]; UINavigationController *navController = self.customNavigationController; navController.viewControllers = [NSArray arrayWithObject:controller] 

Вы также можете переопределить метод drawLayer:inContext: в classе категории UINavigationBar . Внутри drawLayer:inContext: метод, вы можете нарисовать фоновое изображение, которое хотите использовать.

 - (void) drawLayer:(CALayer *)layer inContext:(CGContextRef)context { if ([self isMemberOfClass:[UINavigationBar class]] == NO) { return; } UIImage *image = (self.frame.size.width > 320) ? [UINavigationBar bgImageLandscape] : [UINavigationBar bgImagePortrait]; CGContextClip(context); CGContextTranslateCTM(context, 0, image.size.height); CGContextScaleCTM(context, 1.0, -1.0); CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), image.CGImage); } 

И в качестве полного демонстрационного проекта Xcode по настройке внешнего вида UINavigationBar это и может быть полезно.

Внедрение категории не будет работать в iOS5, вы должны использовать совет Uddhav Kambli для использования CustomNavbar в iOS ≤ 5.

Я просто нашел эту запись в блоге, описывая эту тему очень просто: http://web0.at/blog/?p=38

это мне очень помогло, они используют метод «drawRect», чтобы получить настройку фона.

Для всех тех, кто испытывает проблемы с пользовательскими фонов UINavigationBar в iOS5, выполните это в соответствующих методах viewDidLoad:

 #if defined(__IPHONE_5_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_5_0 if ([self.navigationController.navigationBar respondsToSelector:@selector( setBackgroundImage:forBarMetrics:)]){ [self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"TitleBar"] forBarMetrics:UIBarMetricsDefault]; } #endif 

Обратите внимание, что в моем случае фоновое изображение было названо «TitleBar». Вы можете поместить все свое собственное фоновое изображение.

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

Вы можете установить заголовок каждого представления в своем стеке навигации пустым, но некоторые представления заставляют заголовок, что вы ничего не можете сделать (например, фотосъемщик). Таким образом, вы можете создать альтернативное изображение на навигационной панели с тем же цветом или дизайном, что и логотип Navbar, но с пустой областью, чтобы освободить место для наложенных заголовков.

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

  YourAppDelegate* theApp = (YourAppDelegate*)[[UIApplication sharedApplication] delegate]; UIImage* image = [UIImage imageNamed:theApp.navBarName]; 

Затем в первом controllerе представления, который вы нажмете на стек навигации, сделайте что-то вроде этого:

 - (void)viewWillAppear:(BOOL)animated { YourAppDelegate* theApp = (YourAppDelegate*)[[UIApplication sharedApplication] delegate]; theApp.navBarName = @"navBar_plain"; } 

Затем в controllerе корневого представления сделайте то же самое, но укажите свое навигационное изображение с логотипом, и оно будет восстановлено, когда пользователь перейдет к нему, и нет противоречивого названия.

Другой подход – использовать делегат UINavigationController. Он не требует подclassа / перезаписывания classа UINavigationBar:

 /* in the place where you init the navigationController: fixer = [[AENavigationControllerDelegate alloc] init]; navigationController.delegate = fixer; */ @interface AENavigationControllerDelegate : NSObject  @end @implementation AENavigationControllerDelegate #define bgImageTag 143 - (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { //this is for the future for implementing with the appearance api: if ([[navigationController navigationBar] respondsToSelector:@selector(setBackgroundImage:forBarMetrics:)]) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ [[navigationController navigationBar] setBackgroundImage:[UIImage imageNamed:@"header-logo-bg.png"] forBarMetrics:UIBarMetricsDefault]; }); } else { UIImageView* imageView = (UIImageView*)[navigationController.navigationBar viewWithTag:bgImageTag]; if(!imageView) { UIImage *image = [UIImage imageNamed:@"header-logo-bg.png"]; imageView = [[[UIImageView alloc] initWithImage:image] autorelease]; imageView.tag = bgImageTag; } [navigationController.navigationBar insertSubview:imageView atIndex:0]; } } @end 

https://gist.github.com/1184147

В iOS5 zPosition значение zPosition (самого глубинного слоя UINavigationBar's ). Поэтому, если вы измените это zPosition , работает старый способ.

например.

 UINavigationBar *_bar = navigationController.navigationBar; // Insert ImageView UIImage *_img = [UIImage imageNamed:@"navibar.png"]; UIImageView *_imgv = [[[UIImageView alloc] initWithImage:_img] autorelease]; _imgv.frame = _bar.bounds; UIView *v = [[_bar subviews] objectAtIndex:0]; v.layer.zPosition = -FLT_MAX; _imgv.layer.zPosition = -FLT_MAX+1; [_bar insertSubview:_imgv atIndex:1]; 

Этот скрипт обрабатывает вид представления, поэтому вы должны импортировать QuartzCore .

Вот альтернативное решение, которое позволяет вам использовать свой собственный подclass UINavigationBar:

https://gist.github.com/1253807

Как уже говорило Apple, неверно переопределять методы в Категории. Таким образом, лучший способ настройки фона UINavigarionBar – это метод подclassа и переопределения -(void)drawInRect:

 @implementation AppNavigationBar - (void)drawRect:(CGRect)rect { UIImage *patternImage = [UIImage imageNamed:@"image_name.png"]; [patternImage drawInRect:rect]; } 

Чтобы использовать этот настраиваемый UINavigationBar он должен быть установлен как свойство navigationBar вашего UINavigationBarController . Как вы знаете, это свойство доступно только для чтения. Итак, что нужно сделать:

 - (void)viewDidLoad { [super viewDidLoad]; AppNavigationBar *nav = [AppNavigationBar new]; [self setValue:nav forKey:@"navigationBar"]; } 

Он работает как для iOS 5, так и для 4.3.

Вы можете подclassифицировать UINavigationBar и включить его так, так как категории для drawRect больше не будут работать в iOS5

  navigationController = [[((^ { NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:[NSKeyedArchiver archivedDataWithRootObject:navigationController]]; [unarchiver setClass:[SAPHUINavigationBar class] forClassName:@"UINavigationBar"]; [unarchiver setClass:[UIViewController class] forClassName:NSStringFromClass([navigationController.topViewController class])]; return unarchiver; })()) decodeObjectForKey:@"root"] initWithRootViewController:navigationController.topViewController]; 

Для статического представления (без анимации вообще) я использую стандартную iOS setBackgroundImage

Но когда у меня есть представление, которое анимируется (наиболее вероятно изменение размера), я создаю пользовательский UIImageView и добавляю его в navigationBar, чтобы у меня была большая гибкость над ним

Дело в том, что если вы просто добавите его, он будет на вершине кнопок и titleView, поэтому я вручную сохраню копию большинства подзаголовков, удалю их из родительского представления, добавлю свой ImageView и добавлю все подзоны назад

Это работает для меня

  UIImageView *navBackground = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"navigationBackgroundSample.jpg"]]; UIView *tempTitleView = [[self.navigationBar.subviews objectAtIndex:1] autorelease]; [[self.navigationBar.subviews objectAtIndex:1] removeFromSuperview]; [self.navigationBar addSubview:navBackground]; [self.navigationBar addSubview:tempTitleView]; self.navigationBar.clipsToBounds = YES; [navBackground release]; 

В этом случае у меня нет кнопок, и я узнал, что мой titleView находится в индексе 1, если у вас есть кнопки, они должны быть где-то в массиве subviews navigationBar

Я не знаю, что у индекса 0, я не знаю, может ли это работать по делу, у вас есть текстовое название …

  • NSDateFormatter и yyyy-MM-dd
  • С ARC, что лучше: alloc или autorelease инициализаторы?
  • Метод Swizzle на устройстве iPhone
  • Как сделать естественный вид на NSArray?
  • Можем ли мы пригласить людей использовать наше приложение или отправить запрос друга из приложения через Facebook в iOS 5?
  • Как скопировать объект в объекте c
  • Как масштабировать UIImageView пропорционально?
  • Редактирование Info.plist возможно программно?
  • Как отсортировать NSMutableArray с помощью sortedArrayUsingDescriptors?
  • Данные о сердечном ритме на яблоне
  • Как я могу нажать кнопку за прозрачным UIView?
  • Давайте будем гением компьютера.