UINavigationBar topItem / items, кажется, дважды всплывает на спине - PullRequest
5 голосов
/ 13 октября 2010

Я управляю своим собственным UINavigationBar. Мне нужно сделать это из-за обширных шкур. Документация для UINavigationController предупреждает, что существуют ограничения на создание скина для UINavigationBar при использовании с UINavigationController.

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

Элемент, добавленный в UINavigationController в awakeFromNib, должен никогда быть удален. По какой-то причине его удаляют.

Есть два похожих вопроса, но ни на один из них нет удовлетворительных ответов. Два вопроса:

Метод доступа UINavigationBar .items не возвращает текущий элемент UINavigationItem

UINavigationBar, кажется, выталкивает 2 элемента из стека на "заднюю часть"

- (void)awakeFromNib {
    [headerView setDelegate: self];
    [headerView pushNavigationItem: tableDisplay animated: NO];
}

- (void) selectedStory: (NSNotification *)not {
    [headerView pushNavigationItem: base animated: NO];
    NSLog(@"Selected story: %@", base);
}

- (void) baseNav {
    NSLog(@"Current items: %@", [headerView items]);
    BaseInnerItem *current = (BaseInnerItem *)[headerView topItem];
    [self addSubview: [current view]];
}

- (BOOL)navigationBar: (UINavigationBar *)navigationBar shouldPushItem: (UINavigationItem *)item {
    return YES;
}

- (BOOL)navigationBar: (UINavigationBar *)navigationBar shouldPopItem: (UINavigationItem *)item {
    return YES;
}

- (void)navigationBar:(UINavigationBar *)navigationBar didPushItem:(UINavigationItem *)item {
    NSLog(@"didPushItem: %@", item);
    [self baseNav];
}

- (void)navigationBar:(UINavigationBar *)navigationBar didPopItem:(UINavigationItem *)item {
    NSLog(@"didPopItem: %@", item);
    [self baseNav];
}

Отредактировано для добавления соответствующей отладки из одного прогона:

2010-10-13 02:12:45.911 Remix2[17037:207] didPushItem: <TableDisplay: 0x5d41cc0>
2010-10-13 02:12:45.912 Remix2[17037:207] Current items: (
    "<TableDisplay: 0x5d41cc0>"
)
2010-10-13 02:12:49.020 Remix2[17037:207] didPushItem: <WebDisplay: 0x591a590>
2010-10-13 02:12:49.021 Remix2[17037:207] Current items: (
    "<TableDisplay: 0x5d41cc0>",
    "<WebDisplay: 0x591a590>"
)
2010-10-13 02:12:49.023 Remix2[17037:207] Selected story: <WebDisplay: 0x591a590>
2010-10-13 02:12:59.498 Remix2[17037:207] didPopItem: <WebDisplay: 0x591a590>
2010-10-13 02:12:59.499 Remix2[17037:207] Current items: (
)

Ответы [ 2 ]

0 голосов
/ 15 сентября 2017

Похоже, что это ошибка в реализации -[UINavigationBar items]

При вызове из метода делегата -navigationBar:didPopItem: последний объект будет пропущен.Вы можете проверить это, вызвав [navigationBar valueForKey:@"_itemStack"], чтобы получить базовый массив и увидеть, что ожидаемые элементы все еще там.

Добавление метода dispatch_async в -navigationBar:didPopItem: успешно решает проблему в моем приложении.

0 голосов
/ 06 февраля 2011

Вы всегда должны вызывать [super awakeFromNib], когда ваш подкласс реализует этот метод, согласно документации для -awakeFromNib:

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

Важно, однако, что ...

Я не понимаю, почему вы фактически должны управлять своей собственной панелью навигации.Если вы создаете подкласс UINavigationBar и переопределяете только определенные методы рисования или макета, такие как -drawRect:, -layoutSubviews и т. Д., Тогда вся логика управления панелью навигации в контроллере навигации просто вернется к исходному UINaviationBar class.

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

Между прочим, на самом деле гораздо проще создать обложку для всего приложения без создания подклассов, если все, что вы делаете, - это использование пользовательских графических ресурсов.Установив свойство contents слоя, вы можете либо настроить внешний вид класса UIView на основе требований, либо по всему вашему приложению:

#import <QuartzCore/QuartzCore.h>
...
- (void)viewDidLoad
{
    [super viewDidLoad];

    UIImage * navigationBarContents = [UIImage imageNamed:@"navigation-bar"];
    self.navigationController.navigationBar.layer.contents =    
        (id)navigationBarContents.CGImage;
}

Вы можете установитьсодержимое для любого класса, который наследуется от UIView: панели навигации, панели инструментов, кнопки и т. д. Управлять этим способом намного проще, не имея подклассов вообще.

...