Подтвердить что ты не робот

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

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

Я нашел эту цепочку

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

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

4b9b3361

Ответ 1

Вам просто нужно перегрузить 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

Ответ 2

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

@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 и изменить класс navigationBar на "CustomNavigationBar".

Ответ 3

Вы должны использовать прокси-сервер "внешний вид" для изменения фона и других свойств стиля элементов управления, таких как 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 для устройств 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.

Ответ 4

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

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

Eg.

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

Ответ 5

Вы также можете переопределить метод drawLayer:inContext: в классе категории 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 this и this может быть полезно.

Ответ 6

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

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

Ответ 7

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

Ответ 8

Для всех тех, кто испытывает проблемы с пользовательскими фреймами 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". Вы можете поместить все свое собственное фоновое изображение.

Ответ 9

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

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

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

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

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

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

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

Ответ 10

Другой подход - использовать делегат UINavigationController. Это не требует подкласса/перезапись класса UINavigationBar:

/*
 in the place where you init the navigationController:
 fixer = [[AENavigationControllerDelegate alloc] init];
 navigationController.delegate = fixer;
*/

@interface AENavigationControllerDelegate : NSObject <UINavigationControllerDelegate>
@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

Ответ 11

В iOS5 изменяется значение 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];

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

Ответ 12

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

https://gist.github.com/1253807

Ответ 13

Как уже говорило Apple, неверно переопределять методы в Категории. Таким образом, лучший способ настройки фона UINavigarionBar - это подклассу и переопределить метод -(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.

Ответ 14

Вы можете подклассифицировать 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];

Ответ 15

Для статического представления (без анимации вообще) я использую стандартную 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];

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

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