【问题标题】:UINavigationController popToRootViewController doesn't reset Title, clear backbuttonUINavigationController popToRootViewController 不重置标题,清除后退按钮
【发布时间】:2011-05-12 11:33:47
【问题描述】:

我一直在尝试自定义 UINavigationController 的后退按钮。 在 RootViewController 中,我在 viewDidLoad 中设置了 self.title,并且该字符串出现在导航栏中。在-didSelectRowAtIndexPath 我创建子视图控制器,配置后退按钮并调用-pushViewController。对子的处理会将子视图控制器推入堆栈;我需要返回按钮来弹出到初始视图,就像从第一个子视图控制器返回时一样。当前的后退按钮将弹出到前一个视图,因此如果堆栈上有 5 个子视图控制器,我必须按 5 次后退按钮才能进入根视图。 显示后退按钮时,我无法启动操作。在子 VC 中我可以popToRootViewController;但是,后退按钮现在出现在根视图(!)上,我必须再次点击后退按钮才能恢复原始标题并删除后退按钮。 这是根-viewDidLoad的一部分:

- (void)viewDidLoad {
    self.title = @"My Nav Bar Title";     // displays on root navigation bar title
    // some setup code...
    [super viewDidLoad];
}

这是-didSelectRowAtIndexPath 的一部分,其中选择一个表格视图单元格会导致子视图被推入堆栈:

- (void)tableView:(UITableView *)tableView 
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
   ChildVC *child = [[ChildVC alloc]
                             initWithNibName:@"Child"
                             bundle:nil];

    [self.navigationController dismissModalViewControllerAnimated:YES]; 
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Quiz" style:UIBarButtonItemStylePlain target:self action:@selector(backToMenu)];
    self.navigationItem.backBarButtonItem = backButton;
    [backButton release];

    [self.navigationController pushViewController:child
                                          animated:YES];
     [child release];
}

这是按下后退按钮时不会触发的操作方法:

-(void)backToMenu {
    NSLog(@" in root backToMenu");
    [self.navigationController popViewControllerAnimated:YES];
}

ChildVC 还将在其-didSelectRowAtIndexPath 中创建一个新子控制器,并将新的子控制器推送为下一个子“页面”:

- (void)tableView:(UITableView *)tableView 
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    Child *newChild = [[Child alloc]
                             initWithNibName:@"Child"
                             bundle:nil];

    [self.navigationController dismissModalViewControllerAnimated:YES]; 
    [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
    self.title = self.quizString;  // child view correctly displays customized title

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] 
                                   initWithTitle:@"Quiz" 
                                   style:UIBarButtonItemStylePlain 
                                   target:self 
                                   action:@selector(backToMenu)];
    self.navigationItem.backBarButtonItem = backButton;
    [backButton release];

    [self.navigationController pushViewController:newQuestion
                                         animated:YES];
    [newChild release];
}

在 Child -viewWillDisappear 中,我设置了一个全局变量,因此我知道何时推送新子项以及何时弹回 root:

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:YES];
    if (startOver) {
          [self backToMenu];
    }
}

Child -backToMenu:
-(void)backToMenu {
    [self.navigationController popToRootViewControllerAnimated:YES];
}

这是在 Child 中按下后退按钮时的顺序:

-- 调用子 -viewWillDisappear,调用 -backToMenu -- -backToMenu 调用popToRootViewControllerAnimated: -- 再次调用子 -viewWillDisappear,调用 -backToMenu -- 根-viewWillAppear 被调用 -- 控制返回到 Child -backToMenu

根视图正确显示,但导航栏包含返回按钮和标题,就像它仍然是子视图一样。按后退按钮会删除后退按钮并恢复原始标题。

我怎样才能做到这一点?理想情况下,我希望堆栈上只有 1 个子视图,但我不知道如何;然后后退按钮将返回到根视图。但是当我尝试这个时,我得到了NSInvalidArgumentException',原因:'不支持多次推送同一个视图控制器实例......'

还有,为什么按下后退按钮时没有触发动作?非常感谢任何帮助...谢谢

【问题讨论】:

    标签: uinavigationcontroller uinavigationbar uibarbuttonitem


    【解决方案1】:
    UIBarButtonItem *btnBack=[[UIBarButtonItem alloc]initWithTitle:@"" style:UIBarButtonItemStyleDone target:self action:@selector(back:)] ;
        self.navigationItem.leftBarButtonItem=btnBack;
        //Add image on back button
        UIImage *backButtonImage = [[UIImage imageNamed:@"btn_back.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 6)];
        [btnBack setBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
    

    将此代码放入您的视图控制器[initWithNibName method]form 您要在 根视图控制器

    弹出的位置
    - (void) back : (id)sender
    {
    
     [self.navigationController popToRootViewControllerAnimated:YES];
    
    }
    

    【讨论】:

      【解决方案2】:

      嗯,你的 backButton 调用 popToRootViewController,它调用 viewWillDissapear,如果 startOver 为 true,它调用 popToRootViewController AGAIN? 如果它是假的会发生什么?它继续前面调用的popToRootViewController ...

      backButton->popToRoot->viewWillDissapear->check startOver
      ->YES->popToRoot->viewWillDissapear again->check startOver again->??
      ->NO->continue the disappearing of the view that was called also by popToRoot
      

      如果有多余的,不是因为它的两个分支都继续之前popToRoot或再次调用popToRoot

      为什么不先测试 startOver(在你的 backToMenu 中),然后 popToRootViewController 如果为真?

      【讨论】: