Подтвердите кнопку возврата на UINavigationController - PullRequest
12 голосов
/ 19 декабря 2011

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

Любые идеи?

Ответы [ 6 ]

22 голосов
/ 19 декабря 2011

К сожалению, вы не можете перехватить кнопку возврата таким образом.Ближайшим факсимильным аппаратом является использование собственного UIBarButtonItem, установленного на navigationItem.leftBarButtonItem, и установки действия для отображения вашего предупреждения и т. Д. У меня был графический дизайнер, создающий изображения кнопок, которые выглядят как стандартные кнопки возврата.

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

10 голосов
/ 29 июня 2012

Как я обошел эту ситуацию, установив для leftBarButtonItem стиль UIBarButtonSystemItemTrash (благодаря которому стало очевидным, что они будут удалять черновой элемент) и добавив представление предупреждений, подтверждающее удаление.Поскольку вы устанавливаете пользовательский leftBarButtonItem, он не будет работать как кнопка возврата, поэтому он не будет автоматически отображать представление!

В коде:

- (void)viewDidLoad
{
    // set the left bar button to a nice trash can
    self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemTrash
                                                                                          target:self
                                                                                          action:@selector(confirmCancel)];
    [super viewDidLoad];
}

- (void)alertView:(UIAlertView *)alertView willDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if (buttonIndex)
    {
        // The didn't press "no", so pop that view!
        [self.navigationController popViewControllerAnimated:YES];
    }
}

- (void)confirmCancel
{
    // Do whatever confirmation logic you want here, the example is a simple alert view
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Warning"
                                                    message:@"Are you sure you want to delete your draft? This operation cannot be undone."
                                                   delegate:self
                                          cancelButtonTitle:@"No"
                                          otherButtonTitles:@"Yes", nil];
    [alert show];
}

Это действительно так простокак!Я не вижу большой проблемы, tbh: p

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

ОБНОВЛЕНИЕ: Хорошие новости, все!Тем временем я выпустил приложение ( Appcident ) в App Store с таким поведением, и Apple, похоже, не против.

3 голосов
/ 11 мая 2012

На самом деле, вы можете найти вид кнопки «Назад» и добавить к ней UITapGestureRecognizer.

Если вы посмотрите на это изображение: Back button screen Используя этот код:

@interface UIView (debug)
- (NSString *)recursiveDescription;
@end

@implementation newViewController
... 
NSLog(@"%@", [self.navigationController.navigationBar recursiveDescription]);

Вы можете реализоватькак найти кнопку «Вид сзади».Это всегда последний в массиве подпредставлений панели навигации.

2012-05-11 14:56:32.572 backBtn[65281:f803] <UINavigationBar: 0x6a9e9c0; frame = (0 20; 320 44); clipsToBounds = YES; opaque = NO; autoresize = W; layer = <CALayer: 0x6a9ea30>>
   | <UINavigationBarBackground: 0x6aa1340; frame = (0 0; 320 44); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x6aa13b0>>
   | <UINavigationButton: 0x6d6dde0; frame = (267 7; 48 30); opaque = NO; layer = <CALayer: 0x6d6d9f0>>
   |    | <UIImageView: 0x6d70400; frame = (0 0; 48 30); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6d7d0>>
   |    | <UIButtonLabel: 0x6d70020; frame = (12 7; 23 15); text = 'Edit'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6dec0>>
   | <UINavigationItemView: 0x6d6d3a0; frame = (160 21; 0 0); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6d3f0>>
   | <UINavigationItemButtonView: 0x6d6d420; frame = (5 7; 139 30); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x6d6d4e0>>

Итак, я использовал:

UIView *backButton = [[navBar subviews] lastObject];
[backButton setUserInteractionEnabled:YES];

UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(alertMsg)];
[tapGestureRecognizer setNumberOfTapsRequired:1];
[backButton addGestureRecognizer:tapGestureRecognizer];

Нажатие на кнопку "Назад" и вуаля: Back button was tapped

1 голос
/ 19 октября 2017

Вот обходной путь: (протестировано на iOS10 и 11)

Добавить распознаватель жестов касания на панель навигации:

let tap = UITapGestureRecognizer(target: self, action: #selector(onBackPressed(gestureRecognizer:)))
tap.cancelsTouchesInView = true
self.navigationController?.navigationBar.addGestureRecognizer(tap)

cancellsTouchesInView = true гарантирует, что кнопка возврата не получит событие касания.

Обработка жеста:

@objc func onBackPressed(gestureRecognizer: UITapGestureRecognizer) {
    guard gestureRecognizer.location(in: gestureRecognizer.view).x < 100 else {
        return
    }
    // ... back button is pressed do what you wanted to

Вместо использования 100 в качестве магического числа вы можете найти представление, содержащее кнопку «Назад», и использовать его рамку, чтобы обнаружить прикосновения к ней.

0 голосов
/ 13 декабря 2018

Легко, peasy. Просто закройте кнопку прозрачным UIControl и запишите прикосновения.

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

#define COVER_HEIGHT    44
    //make this an iVar:  UIControl *backCover;
    if ( backCover == nil ) {
        CGRect cFrame = CGRectMake( 0, self.view.frame.origin.y-COVER_HEIGHT, 100, COVER_HEIGHT);
        backCover = [[UIControl alloc] initWithFrame:cFrame]; // cover the back button
        backCover.backgroundColor = [[UIColor orangeColor] colorWithAlphaComponent:0.2]; // transparent
        // use clearColor later
        [backCover addTarget:self action:@selector(backCoverAction:)
            forControlEvents:UIControlEventTouchDown];
        [self.view.window addSubview:backCover];
    }
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];

    [backCover removeFromSuperview]; // prevent coverage on another view
    backCover = nil;
}

- (void)backCoverAction:(UIControl *)sender
{
    // decide what to do -- maybe show a dialog.
    // to actually go "Back" do this:
    [self.navigationController popViewControllerAnimated:YES]; // "Back"
}

Эта схема также работает для кнопок tabBar, но более сложно определить местоположение.

0 голосов
/ 30 августа 2012

Вот что вам нужно сделать, чтобы легко создать пользовательскую кнопку «Назад», которая повторяет внешний вид кнопки «Назад» по умолчанию на iPhone и iPad, с явным кодом, написанным потому, что, я думаю, я приду сюда, чтобы найти это снова в какой-то момент ,

Поместите следующие функции где-нибудь в файле реализации (.m) соответствующего UIViewController с UINavigationController, а затем в viewDidLoad запустите [self setupBackButton];

Что бы вы не хотели делать с кнопкой «Назад», включите функцию backButtonPressed.

- (void)setupBackButton {
    UIImage *leftArrowImage;
    UIImage *pressedLeftArrowImage;
    UIButton *customBackButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, 48, 30)];
    [customBackButton setAutoresizingMask:UIViewAutoresizingNone];
    customBackButton.titleLabel.font=[UIFont boldSystemFontOfSize:12];
    [customBackButton setTitle:@"Back" forState:UIControlStateNormal];
    [customBackButton setTitleColor:[UIColor lightGrayColor] forState:UIControlStateDisabled];
    [customBackButton setTitleEdgeInsets:UIEdgeInsetsMake(0, 5, 0, 0)];

    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        leftArrowImage = [UIImage imageNamed:@"UINavigationBarSilverBack.png"];
        pressedLeftArrowImage = [UIImage imageNamed:@"UINavigationBarSilverBackPressed.png"];
    }
    else {
        leftArrowImage = [UIImage imageNamed:@"UINavigationBarDefaultBack.png"];
        pressedLeftArrowImage = [UIImage imageNamed:@"UINavigationBarDefaultBackPressed.png"];
    }
    UIImage *stretchableLeftArrowImage = [leftArrowImage stretchableImageWithLeftCapWidth:15.0 topCapHeight:0];
    UIImage *stretchablePressedLeftArrowImage = [pressedLeftArrowImage stretchableImageWithLeftCapWidth:15.0 topCapHeight:0];
    [customBackButton setBackgroundColor:[UIColor clearColor]];
    [customBackButton setBackgroundImage:stretchableLeftArrowImage forState:UIControlStateNormal];
    [customBackButton setBackgroundImage:stretchablePressedLeftArrowImage forState:UIControlStateHighlighted];
    [customBackButton addTarget:self action:@selector(backButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
    UIBarButtonItem *aCustomBackButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customBackButton];
    [[self navigationItem] setLeftBarButtonItem:aCustomBackButtonItem];
}

- (void)backButtonPressed:(id)sender {
    NSLog(@"back button pressed");
}

Чтобы получить точные кнопки pngs от iOS, я рекомендую UIKit Artwork Extractor . После запуска проекта и сохранения изображений на симуляторе iPad Retina, а затем на симуляторе iPad без ретина, найдите заголовки в папке «Common» в папке симулятора, которая появится на рабочем столе. Имена файлов «UINavigationBar ... Back (@ 2x) .png» и «UINavigationBar ... BackPressed (@ 2x) .png» - это то, что вам нужно.

Я также прикрепляю стандартную кнопку задней панели iOS (iPhone и iPad) pngs , использованную в приведенном выше коде, для удобства. Обратите внимание, что с обновлениями iOS внешний вид задних barbuttonitems по умолчанию может измениться ...

...