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

Как создать backBarButtomItem с пользовательским представлением для UINavigationController

У меня есть UINavigationController, в который я нажимаю несколько просмотров. Внутри viewDidLoad для одного из этих представлений я хочу установить self.navigationItem.backBarButtonItem в пользовательское представление (на основе пользовательского образа). Я не знаю почему, но, похоже, это не работает. Вместо этого я получаю стандартную кнопку "назад".

UIButton *backButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 63, 30)];
[backButton setImage:[UIImage imageNamed:@"back_OFF.png"] forState:UIControlStateNormal];
[backButton setImage:[UIImage imageNamed:@"back_ON.png"] forState:UIControlStateSelected];
UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
self.navigationItem.backBarButtonItem = backButtonItem;
[backButtonItem release];
[backButton release];

Я тестировал стандартное название и работал. Что не так с вышеуказанным кодом?

self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Prout" style:UIBarButtonItemStyleDone target:nil action:nil] autorelease];

Спасибо за любую помощь в этом.

4b9b3361

Ответ 1

Я уверен, что backBarButtonItem - свойство только для чтения. Вместо изменения backBarButtonItem попробуйте установить пользовательский leftBarButtonItem и скрыть backBarButtonItem:

self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:@"Prout" style:UIBarButtonItemStyleDone target:nil action:nil] autorelease];
self.navigationItem.hidesBackButton = YES;

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

Ответ 2

Как и в iOS5, у нас есть отличный новый способ настройки внешнего вида практически любого элемента управления, используя протокол UIAppearance, т.е. [UIBarButtonItem appearance]. Прокси-сервер внешнего вида позволяет вам создавать изменения приложения для внешнего вида элементов управления. Ниже приведен пример пользовательской кнопки возврата, созданной с помощью прокси-сервера внешнего вида.

enter image description here

Используйте приведенный ниже пример кода, чтобы создать кнопку возврата с пользовательскими изображениями для нормальных и выделенных состояний. Вызовите следующий метод из приложения appDelegate application:didFinishLaunchingWithOptions:

- (void) customizeAppearance {

UIImage *i1 = [[UIImage imageNamed:@"custom_backButton_30px"]
                      resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 6)];
UIImage *i2 = [[UIImage imageNamed:@"custom_backButton_24px"] 
                      resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 6)];

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:i1 
                              forState:UIControlStateNormal 
                              barMetrics:UIBarMetricsDefault];

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:i2 
                              forState:UIControlStateNormal 
                              barMetrics:UIBarMetricsLandscapePhone];

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:i1
                              forState:UIControlStateHighlighted 
                              barMetrics:UIBarMetricsDefault];

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:i2 
                              forState:UIControlStateHighlighted 
                              barMetrics:UIBarMetricsLandscapePhone];
}

Это просто быстрый пример. Обычно вы хотите иметь отдельные изображения для нормального и выделенного (нажатого) состояния.

Если вы заинтересованы в настройке внешнего вида других элементов управления, можно найти несколько хороших примеров: http://ios.biomsoft.com/2011/10/13/user-interface-customization-in-ios-5/

Ответ 3

Я никогда не мог создать правильный UIBarButtonItem с настраиваемым представлением и setBackBarButtonItem.

Вот решение, которое я нашел: пусть net UINavigationControllerDelegate обрабатывает все! Трюк здесь заключается в вызове метода popViewControllerAnimated: для viewController.navigationController, поэтому вам не нужно создавать какой-либо пользовательский метод.

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if([navigationController.viewControllers count ] > 1) {
        UIView *backButtonView = [[UIView alloc] initWithFrame:CGRectMake(0,0,70,35)];
        UIButton *myBackButton = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
        [myBackButton setFrame:CGRectMake(0,0,70,35)];
        [myBackButton setImage:[UIImage imageNamed:@"back.png"] forState:UIControlStateNormal];
        [myBackButton setEnabled:YES];
        [myBackButton addTarget:viewController.navigationController action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];
        [backButtonView addSubview:myBackButton];
        [myBackButton release];
        UIBarButtonItem* backButton = [[UIBarButtonItem alloc] initWithCustomView:backButtonView];
        viewController.navigationItem.leftBarButtonItem = backButton;
        [backButtonView release];
        [backButton release];
    }
}

Ответ 4

Если ваша конечная цель - просто заменить образ, используемый для кнопки "Назад", вы можете использовать новый метод в UIBarButtonItem, доступный в iOS 5.0:

setBackButtonBackgroundImage: Форстат: barMetrics:

Apple Docs: http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIBarButtonItem_Class/Reference/Reference.html

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

UIImage *toolbarBackButtonBackgroundPortrait = [[UIImage imageNamed:@"toolbarBackButtonPortrait"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 17, 0, 6)];
UIImage *toolbarBackButtonBackgroundLandscape = [[UIImage imageNamed:@"toolbarBackButtonLandscape"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 17, 0, 6)];

[[UIBarButtonItem appearance] setBackButtonBackgroundImage:toolbarBackButtonBackgroundPortrait forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:toolbarBackButtonBackgroundLandscape forState:UIControlStateNormal barMetrics:UIBarMetricsLandscapePhone];

Ответ 5

Я был бы готов поспорить, что это ошибка на Apple, поскольку я столкнулся с той же проблемой. Причина в том, что я могу получить пользовательский UIBarButtonItem, но только тогда, когда я не, попытаюсь использовать метод initWithCustomView:. Для API контроллер навигации проверяет следующие вещи при нажатии нового контроллера представления:

  • Если новый контроллер верхнего уровня имеет пользовательский элемент кнопки на панели слева, отображается этот элемент. Чтобы указать элемент пользовательской левой кнопки, установите для свойства leftBarButtonItem элемента навигации диспетчера представлений.
  • Если на контроллере верхнего уровня нет пользовательского элемента левой кнопки, но элемент навигации предыдущего контроллера представления имеет действительный элемент в свойстве backBarButtonItem, на панели навигации отображается этот элемент.
  • Если элемент пользовательской панели не задан ни одним из контроллеров представления, используется кнопка возврата по умолчанию, и ее заголовок устанавливается на значение свойства title предыдущего контроллера представления, то есть контроллер представления один на уровне стека. (Если в стеке навигации имеется только один контроллер вида, кнопка возврата не отображается.)

Мой случай (а также ваш) равен 2. Я указываю код точно так же, как ваш (т.е. создав UIButton, установив его свойства image для разных состояний, создав UIBarButtonItem, инициализируя его с помощью UIButton, а затем установите для моего текущего контроллера представления backBarButtonItem свойство UIBarButtonItem); однако, когда я потом подтолкнул контроллер своего вида, ничего не отображается в левой части моего навигационного контроллера. Как ни странно, я могу щелкнуть, где должна быть кнопка "Назад", и она выталкивает контроллер вида.

Интересно, что если я создаю UIBarButtonItem, используя метод initWithTitle:style:target:action: вместо метода initWithCustomView:, он делает специальную кнопку с пользовательским названием. Кроме того, как отметил Тревис, использование свойства leftBarButtonItem работает просто отлично. Однако я предпочел бы придерживаться санкционированной логики, указав кнопку "Назад" для текущего контроллера представлений - отображаться позже при нажатии нового контроллера представления - вместо создания левой кнопки для следующего контроллера представления, который, возможно, не должен заботиться ни о чем, относящемся к контроллеру представлений, который был до него.: -\

Ответ 6

Установите backBarButtonItem до, нажав на viewController с помощью navigationController. Установка backBarButtonItem в viewDidLoad не работает.

Скажем, у меня есть MyTableViewController. Когда пользователь удаляет определенную строку, я хочу нажать AnotherViewController с помощью navigationController. Код выглядит примерно так:

// in MyTableViewController tableView:didSelectRowAtIndexPath method...
UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                               initWithImage:[UIImage imageNamed:@"yourImage.png"]
                                       style:UIBarButtonItemStyleBordered 
                                      target:nil 
                                      action:nil];

self.navigationItem.backBarButtonItem = backButton;
[backButton release];

[self.navigationController pushViewController:anotherViewController];

Когда отображается другой экран управления, кнопка возврата на панели навигации будет иметь @"yourImage.png" и стиль кнопки назад по умолчанию (прямоугольная стрелка). Также обратите внимание на то, чтобы передать nil как target. Кнопка ведет себя как кнопка "Назад".

Ответ 7

Даже если это уже ответ, это сработало для меня:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"backArrow.png"] style:UIBarButtonItemStyleBordered target:nil action:nil];
self.navigationItem.backBarButtonItem = backButton;
[backButton release];

Кстати: даже в iOS4, инициализирующем мою кнопку с помощью initWithCustomView: не работала для меня.; (

Ответ 8

У меня также были проблемы с customView на navigationItem.backBarButtonItem. Я подозреваю, что это возможно просто в SDK.

В то время как обходные пути, изложенные здесь, действительно работают, я придумал более элегантное решение: он все еще использует navigationItem.leftBarButtonItem, но позаботится об этом для вас автоматически (больше не нужно "детское" представление контроллеры должны знать что-либо о своем "родительском" и/или вручную установить navigationItem.leftBarButtonItem).


Прежде всего, пусть какой-то класс будет UINavigationControllerDelegate для UINavigationController, чья обратная кнопка вам интересна. Затем в этом классе настройте что-то вроде следующего метода willShowViewController delegate:

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated{
    // reference to view controller stack
    NSArray *viewControllers = [ navigationController viewControllers ];
    if( [ viewControllers count ] > 1 ){
        // the view controller we'll be linking to
        UIViewController *backViewController = [ viewControllers objectAtIndex: [ viewControllers count ] - 2 ];
        // create custom UIBarButtonItem
        UIBarButtonItem *leftButton = [[ UIBarButtonItem alloc ] initWithCustomView: someCustomView ];
        // set it as the leftBarButtonItem on the incoming viewcontroller
        viewController.navigationItem.leftBarButtonItem = leftButton;
        // tidy up
        [ leftButton release ];
    }
}

У меня были некоторые проблемы с этим; кажется, что UIBarButtonItem.action и UIBarButtonItem.target не работают, когда он a navigationItem.leftBarButtonItem. Итак, у вас осталась пользовательская кнопка "назад", которая на самом деле не возвращается. Я оставляю ответ на касания в вашем пользовательском представлении как упражнение для читателя (я использовал UIButton), но вам нужно добавить этот метод в свой класс делегата:

-(void)onDummyBackButtonTapped{
    [ someNavigationController popViewControllerAnimated: YES ];
}

и подключите его, чтобы запустить, когда ваш пользовательский вид прослушивается.

Ответ 9

backBarButtonItem не доступен только для чтения имущество. Я не уверен, почему он ведет себя так странно, и вышесказанное является действительным (если меньше, чем идеальный).

Это ведет себя странно, потому что установка vc backBarButtonItem ничего не меняет о появлении элемента навигации vc - вместо этого он меняет кнопку, указывающую BACK на vc. См. обновление панели навигации от Apple FMI.

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

Ответ 10

Элемент navigationController backBarButtonItem устанавливается на элемент, название которого вы пытаетесь повлиять.

то есть., например, viewdidLoad:

self.title = @"Page 1 of 4";

self.navigationItem.backBarButtonItem =
[[[UIBarButtonItem alloc] initWithTitle:@"Page 1"
                                  style:UIBarButtonItemStyleBordered
                                 target:nil
                                 action:nil] autorelease];

Вы не могли переопределить это на странице.

Документация для UINavigationItem: backBarButtonItem делает это ясно:

Когда этот элемент является обратным элементом панель навигации - когда это следующий элемент ниже верхнего элемента - это может быть представленный в качестве кнопки "Назад" на Панель навигации. Используйте это свойство для укажите кнопку "Назад". Цель и действие элемента кнопки задней панели вы устанавливаете должно быть nil. По умолчанию Значение - это отображение позиции панели заголовок пунктов навигации.

Ответ 11

Вот как я создаю пользовательскую квадратную кнопку со стрелкой вместо обычного текста.

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

Итак, AppDelegate.m(ARC):

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    ((UINavigationController*)_window.rootViewController).delegate = self;
    return YES;
}

#pragma mark - UINavigationControllerDelegate

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if(navigationController.viewControllers.count > 1) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        [button setImage:[UIImage imageNamed:@"back-arrow.png"] forState:UIControlStateNormal];
        [button setBackgroundColor:[UIColor grayColor]];
        button.frame = CGRectMake(0, 0, 44, 44);
        viewController.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:button];
        [button addEventHandler:^(id sender) {
            [navigationController popViewControllerAnimated:YES];
        } forControlEvents:UIControlEventTouchUpInside];
    }
}

Я использую BlocksKit, чтобы поймать событие нажатия кнопки. Это очень удобно для таких вещей, но вы также можете использовать обычный addTarget: действие: forControlEvents: method

Ответ 12

Думаю, я нашел решение для этого. Просто установите кнопку на элементе навигации на предыдущем контроллере (тот, который вы хотите вернуться)

Итак, если у меня есть, например, корневой контроллер и я нажимаю второй контроллер и хочу настроить кнопку "Назад", тогда я должен сделать следующее:

self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc]
    initWithImage:[UIImage imageNamed:@"ico.png"] style:UIBarButtonItemStyleBordered
    target:nil action:nil] autorelease];

Если self - это контроллер корневого представления, а не второй.

Ответ 13

Моя логика:

  • Создайте настраиваемую кнопку (также известный подклассом)
  • Инициализировать элемент панели с помощью настраиваемой кнопки/вида
  • Добавьте действие, которое позволяет нам вернуться к нашему предыдущему контроллеру представления.
  • Установите элемент кнопки левой панели на этот элемент созданной пользовательской панели.
  • Скрыть элемент кнопки задней панели контроллера вида, на который вы нажимаете

Шаг 3 был важен. Я решил, что самый чистый способ имитации "вернуться" состоял в том, чтобы просто использовать метод UINavigationController (popViewControllerAnimated:). Таким образом, я просто добавляю это действие к navigationController viewController, который я нажимаю (viewControllerToPush) следующим образом:

[navItemButton addTarget:viewControllerToPush.navigationController action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];

Пример:

UIViewController *viewControllerToPush = [[UIViewController alloc] init];
UIImage *navImage = [UIImage imageNamed:@"your_back_button_image"];

UIButton *navItemButton = [UIButton buttonWithType:UIButtonTypeCustom];
[navItemButton setImage:navImage forState:UIControlStateNormal];
[navItemButton setImage:navImage forState:UIControlStateHighlighted];
[navItemButton setFrame:CGRectMake(0, 0, navImage.size.width, navImage.size.height)];

[navItemButton addTarget:viewControllerToPush.navigationController action:@selector(popViewControllerAnimated:) forControlEvents:UIControlEventTouchUpInside];

UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithCustomView:navItemButton];

viewControllerToPush.navigationItem.leftBarButtonItem = barButtonItem;
viewControllerToPush.navigationItem.hidesBackButton = YES;
[self.navigationController pushViewController:viewControllerToPush animated:YES];

Ответ 14

Вы можете использовать элемент leftBarButtonItem вместо элемента кнопки "Назад". И чтобы удалить элемент кнопки "Назад" по умолчанию, установите его равным nil следующим образом:

navigationController?.navigationBar.backIndicatorImage = nil
navigationController?.navigationBar.backIndicatorTransitionMaskImage = nil

let button = UIButton.init(type: .custom)
button.imageView?.contentMode = UIViewContentMode.scaleAspectFit
button.setImage(UIImage.init(named: "top_back"), for: UIControlState.normal)
button.frame = CGRect.init(x: 0, y: 0, width: 75, height: 50) 
button.addTarget(self, action: #selector(handleBackButton), for: .touchUpInside)

let barButton = UIBarButtonItem.init(customView: button)
self.navigationItem.leftBarButtonItem = barButton