在 viewWillDisappear 期间隐藏 UINavigationController 的 UIToolbar:

发布于 2024-08-22 21:07:59 字数 841 浏览 9 评论 0原文

我有一个带有 UITableView 菜单的 iPhone 应用程序。当选择表中的一行时,相应的视图控制器就会被推送到应用程序的 UINavigationController 堆栈上。

我的问题是 MenuViewController 不需要工具栏,但推入堆栈的 UIViewControllers 需要。每个被推送的 UIViewController 都会调用 viewDidAppear: 中的 setToolbarHidden:animated:。为了隐藏工具栏,我在 viewWillDisappear: 中调用 setToolbarHidden:animated:

显示工具栏有效,这样当推送的视图出现时,工具栏会向上滑动并且视图可以正确调整大小。但是,当按下后退按钮时,工具栏会向下滑动,但视图不会调整大小。这意味着当其他视图过渡时,视图底部有一条黑色条带。我尝试在隐藏工具栏之前将工具栏的高度添加到视图的高度,但这会导致视图在过渡,以便仍然有一个黑条。

我意识到我可以管理自己的 UIToolbar,但为了方便起见,我想使用 UIToolbar 中内置的 UINavigationControllers

这个论坛帖子提到了同样的问题,但没有提到解决方法。

I've got an iPhone application with a UITableView menu. When a row in the table is selected, the appropriate view controller is pushed onto the application's UINavigationController stack.

My issue is that the MenuViewController does not need a toolbar, but the UIViewControllers which are pushed onto the stack do. Each UIViewController that gets pushed calls setToolbarHidden:animated: in viewDidAppear:. To hide the toolbar, I call setToolbarHidden:animated: in viewWillDisappear:.

Showing the toolbar works, such that when the pushed view appears the toolbar slides up and the view resizes correctly. However, when the back button is pressed the toolbar slides down but the view does not resize. This means that there's a black strip along the bottom of the view as the other view transitions in. I've tried adding the toolbar's height to the height of the view prior to hiding the toolbar, but this causes the view to be animated during the transition so that there's still a black bar.

I realise I can manage my own UIToolbar, but I'd like to use UINavigationControllers built in UIToolbar for convenience.

This forum post mentions the same issue, but no workaround is mentioned.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

栩栩如生 2024-08-29 21:07:59

我也经历过这个问题。就我而言,我发现成功隐藏工具栏而不显示窗口背景的唯一方法是在视图控制器的 - 中调用 [self.navigationController setToolbarHidden:YESAnimated:animated] viewDidAppear: 方法。

I too have experienced this problem. In my case, the only way I found to successfully hide the toolbar without showing the background of the window is to call [self.navigationController setToolbarHidden:YES animated:animated] in your view controller’s -viewDidAppear: method.

℡Ms空城旧梦 2024-08-29 21:07:59

我对这个问题的答案不满意,所以我发布了自己的答案: 同时引用源视图控制器和目标视图控制器

我得到的答案解决了我的问题。它也可能对你有用(虽然这个问题很老了,但我想这可能会帮助像我这样阅读这篇文章六次寻找提示的人)。

这就是我所做的。我不知道标记协议是否是惯用的 Objective-C,但我将它们比作我在 C# 中使用的属性,所以我有这个标记协议:

@protocol HidesNavigationItem
@end

我将 UINavigationControllerDelegate 添加到我的 AppDelegate 中。我还不确定这是否是一件好事。我考虑过将该实现保留在另一个对象中,但现在,这就是我放置它的地方。这是实现:

#pragma mark Navigation Controller Delegate
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [navigationController setNavigationBarHidden:[viewController conformsToProtocol:@protocol(HidesNavigationItem)] animated:animated];
}

这样,我可以在 UIViewController 实现上设置标记协议,如下所示:

@interface MyViewController : UIViewController <HidesNavigationItem>

如果我没有该接口,它将把它放回去。

最后,在我的 appDelegate 的 application:didFinishLaunchingWithOptions: 方法中,我像这样连接委托:

if ([self.window.rootViewController isMemberOfClass:[UINavigationController class]])
    ((UINavigationController*)self.window.rootViewController).delegate = self;

现在我没有得到黑匣子,也没有柴郡猫。我的解决方案当然是关于导航栏的,但我确信它对于工具栏来说也是一样的。这与 Danra 的答案非常相似,只是我得到的黑匣子没有“动画:动画”。

I wasn't satisfied with the answers on this question so I posted my own: Reference to source view controller and destination view controller at the same time

The answer I got fixed my problem. It may work for yours too (though this question is pretty old, I figured this might help someone like me who read this post a half dozen times looking for a hint).

Here's what I did. I don't know if marker protocols are idiomatic objective-c or not, but I liken them to attributes like I'd use in c# so I have this marker protocol:

@protocol HidesNavigationItem
@end

I added UINavigationControllerDelegate to my AppDelegate. I'm not sure yet whether or not that's a good thing. I thought about keeping that implementation in another object, but for now, this is where I put it. Here's the implementation:

#pragma mark Navigation Controller Delegate
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    [navigationController setNavigationBarHidden:[viewController conformsToProtocol:@protocol(HidesNavigationItem)] animated:animated];
}

This way, I can just set my marker protocol on my UIViewController implementation like so:

@interface MyViewController : UIViewController <HidesNavigationItem>

If I don't have that interface, it puts it back.

Finally, in my appDelegate's application:didFinishLaunchingWithOptions: method, I wire up the delegate like this:

if ([self.window.rootViewController isMemberOfClass:[UINavigationController class]])
    ((UINavigationController*)self.window.rootViewController).delegate = self;

Now I get no black boxes and no Cheshire Cat. My solution was with regard to the navigation bar of course, but I'm sure it works the same for the toolbar. This is very similar to Danra's answer except that I get the black box without the "animated:animated."

夜夜流光相皎洁 2024-08-29 21:07:59

对于推送时不需要工具栏的 UIViewController,您可以考虑使用

为该 UIViewController 实现 hidesBottomBarWhenPushed 方法:

// method to be added to the UIViewController that has no toolbar
- (BOOL) hidesBottomBarWhenPushed {
    return YES;
}

或者在推送 UIViewController 之前,设置 hidesBottomBarWhenPushed 的值:

viewControllerWithNoToolBar.hidesBottomBarWhenPushed = YES
[self.navigationController pushViewController:viewControllerWithNoToolBar animated:YES];

For the UIViewController that does not need a toolbar when pushed you can consider using either

Implementing the hidesBottomBarWhenPushed method for that UIViewController:

// method to be added to the UIViewController that has no toolbar
- (BOOL) hidesBottomBarWhenPushed {
    return YES;
}

Or prior to pushing in the UIViewController, set the value of hidesBottomBarWhenPushed:

viewControllerWithNoToolBar.hidesBottomBarWhenPushed = YES
[self.navigationController pushViewController:viewControllerWithNoToolBar animated:YES];
锦上情书 2024-08-29 21:07:59

尝试实现 UINavigationControllerDelegate 并将其设置为导航控制器的委托属性。
这对我来说实现了您在帖子中描述的内容,没有可见的伪影。

以下代码假设通过在firstController 中执行的操作将secondController 推入导航视图。

MyNavigationControllerDelegate.h

@interface MyNavigationControllerDelegate : NSObject<UINavigationControllerDelegate> {
}

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

@end

MyNavigationControllerDelegate.m

#import "MyNavigationControllerDelegate.h"
#import "AppDelegate_Shared.h"

@implementation MyNavigationControllerDelegate

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if ([AppDelegate_Shared sharedDelegate].firstController  == viewController ) {
        [navigationController setNavigationBarHidden:TRUE];
        [navigationController setToolbarHidden:FALSE];
    }
}

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if ([AppDelegate_Shared sharedDelegate].secondController == viewController ) {
        [navigationController setNavigationBarHidden:FALSE];
        [navigationController setToolbarHidden:TRUE];
    }
}

@end

sharedDelegate 只是一个辅助方法:

AppDelegate_Shared.m

+ (AppDelegate_Shared*)sharedDelegate {
    return (AppDelegate_Shared*)[[UIApplication sharedApplication] delegate];
}

Try implementing a UINavigationControllerDelegate and setting it to your navigation controller's delegate property.
This achieved for me what you are describing in your post, with no visible artifacts.

The following code assumes that secondController is pushed into the navigation view by an action performed in the firstController.

MyNavigationControllerDelegate.h

@interface MyNavigationControllerDelegate : NSObject<UINavigationControllerDelegate> {
}

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;

@end

MyNavigationControllerDelegate.m

#import "MyNavigationControllerDelegate.h"
#import "AppDelegate_Shared.h"

@implementation MyNavigationControllerDelegate

-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if ([AppDelegate_Shared sharedDelegate].firstController  == viewController ) {
        [navigationController setNavigationBarHidden:TRUE];
        [navigationController setToolbarHidden:FALSE];
    }
}

-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated {
    if ([AppDelegate_Shared sharedDelegate].secondController == viewController ) {
        [navigationController setNavigationBarHidden:FALSE];
        [navigationController setToolbarHidden:TRUE];
    }
}

@end

sharedDelegate is just a helper method:

AppDelegate_Shared.m

+ (AppDelegate_Shared*)sharedDelegate {
    return (AppDelegate_Shared*)[[UIApplication sharedApplication] delegate];
}
不回头走下去 2024-08-29 21:07:59

要在新视图控制器中显示工具栏,只需添加以下内容:

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setToolbarHidden:NO animated:animated];
    [super viewWillAppear:animated];
}

要隐藏工具栏:

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setToolbarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}

在屏幕之间移动时,使用以下代码推送新视图控制器:

SettingsRecordingViewController *vc = [[SettingsRecordingViewController alloc] initWithNibName:@"SettingsRecordingViewController" bundle:[NSBundle mainBundle]]; 
[self.navigationController pushViewController:vc animated:YES];      
[vc release];

如果它具有不同的工具栏状态(隐藏/显示),则隐藏/显示工具栏的漂亮动画将是显示。

To show toolbar in new view controller just add this:

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setToolbarHidden:NO animated:animated];
    [super viewWillAppear:animated];
}

To hide toolbar:

- (void)viewWillAppear:(BOOL)animated
{
    [self.navigationController setToolbarHidden:YES animated:animated];
    [super viewWillAppear:animated];
}

When traveling between screens push new view controller with following code:

SettingsRecordingViewController *vc = [[SettingsRecordingViewController alloc] initWithNibName:@"SettingsRecordingViewController" bundle:[NSBundle mainBundle]]; 
[self.navigationController pushViewController:vc animated:YES];      
[vc release];

and if it has different state of toolbar (hidden/shown) then nice animation of hiding/showing toolbar will be shown.

梦在夏天 2024-08-29 21:07:59

这里的问题是 UITableView 的框架被设置为不与 UIToolbar 重叠。也就是说,它位于 UIToolbar 的正上方。当您将下一个 UIViewController 推送到 UINavigationController 堆栈时,同时删除 UIToolbar,除了 UIWindow 之外,没有任何内容可显示。 code> 在它后面,除非你在它的位置放了一些东西

转换后没有尴尬动画的一种解决方法是将您的 UITableView 放置在 UIView “容器”中,该容器与您的常规视图共享相同的框架,但位于 UIToolbar 下方 以及您希望在过渡期间看到的所需颜色(例如白色)。

要实现下重叠,您可以将 UIViewController 设置为 wantsFullScreenLayout = YES。然后,您将确保您的 UITableView 具有与使用容器之前相同的框架。即它位于导航栏下方、工具栏上方。

通过编写自定义 UIViewController 并使用它来代替 UITableViewController,或者偷偷摸摸地插入新的 UIView ,可以使这变得更加优雅”容器”位于现有 UITableViewController 中的 UITableView 下方。

The issue here is that the UITableView's frame is set so that it does not overlap with the UIToolbar. That is, it sits just above the UIToolbar. When you push the next UIViewController to the UINavigationController stack, while removing the UIToolbar, there is nothing to show but the UIWindow behind it, unless you put something there in its place.

One workaround without the awkward animation after transition is to place your UITableView in a UIView "container" that shares the same frame as your regular view, but underlaps the UIToolbar with the desired colour that you wish to see during the transition (e.g. white).

To enact the underlap, you could set your UIViewController to wantsFullScreenLayout = YES. You would then ensure that your UITableView has the same frame as it would have before the use of the container. i.e. it sits below the navigation bar, and above the toolbar.

This can be made more elegant by writing a custom UIViewController and use that instead of the UITableViewController, or by being sneaky and inserting the new UIView "container" beneath the UITableView in your existing UITableViewController.

望笑 2024-08-29 21:07:59

我使用自定义背景图像作为工具栏背景,使用自定义图像作为表格背景。当视图从另一个表格视图来回转换时,我对底部的黑条遇到了同样的问题。不过我

self.navigationController.toolbar.barStyle = UIBarStyleBlackTranslucent;

在viewDidLoad中设置了。

这会将背景图像设置为背景的全部潜在大小,如果您有透明的工具栏,则这是有意义的。当您使用标准的不透明工具栏时,这可能不是一个好的解决方法,但对于那些自定义工具栏的人来说,您可以两全其美。

I use a custom background image for the toolbar background, and a custom image for the table background. I was having the same issue with the black bar at the bottom as the view transitioned back and forth from another table view. However I set the

self.navigationController.toolbar.barStyle = UIBarStyleBlackTranslucent;

in viewDidLoad.

This sets the background image to the full potential size of the background, which if you had a transparent toolbar would make sense. It's probably not a good workaround when you're using the standard opaque toolbar, but for those of you customizing the toolbar anyway, you can get the best of both worlds.

相对绾红妆 2024-08-29 21:07:59

我同意杰夫的回答。但是,如果我在 viewController 的 -viewDidAppear 方法中隐藏工具栏(通过该方法推送不同的 viewController),则会出现 UI 故障。

为了避免这种情况,我进行了实验,发现在 -viewWillAppear 调用中调用 -setToolbarHidden 确实隐藏了工具栏,但正如问题所述,虽然展开的视图不会被表视图行占用。

为了解决这个问题,我已更改为以下代码,现在它可以正常工作了:

- (void)viewDidLoad
{
    [super viewDidLoad];
.
.
.
    [self reframeRowHeight];
    [self.menuItemTableView addObserver:self
                             forKeyPath:@"frame"
                                options:NSKeyValueObservingOptionNew
                                context:nil];
    [self.menuItemTableView setBounces:NO];
.
.
.
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"frame"])
    {
        [self reframeRowHeight];
    }
}

-(void)reframeRowHeight
{

    [self.menuItemTableView setRowHeight:self.menuItemTableView.frame.size.height/self.menuItems.count];
    [self.menuItemTableView reloadData];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
.
.
.
    // Bad Apple! - http://stackoverflow.com/questions/2339721/hiding-a-uinavigationcontrollers-uitoolbar-during-viewwilldisappear
    [self.navigationController setToolbarHidden:YES animated:YES];
.
.
.
}

I am in agreement with Jeff's answer. But there is a UI glitch if I hide the toolbar in -viewDidAppear method of the viewController through which different viewControllers are pushed.

To avoid this, I was experimenting and found out that calling -setToolbarHidden in the -viewWillAppear call indeed hides the toolbar, but as the question states, the view though expanded would not be occupied by the tableview rows.

To fix this, I have changed to following code and now it works without the glitch:

- (void)viewDidLoad
{
    [super viewDidLoad];
.
.
.
    [self reframeRowHeight];
    [self.menuItemTableView addObserver:self
                             forKeyPath:@"frame"
                                options:NSKeyValueObservingOptionNew
                                context:nil];
    [self.menuItemTableView setBounces:NO];
.
.
.
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"frame"])
    {
        [self reframeRowHeight];
    }
}

-(void)reframeRowHeight
{

    [self.menuItemTableView setRowHeight:self.menuItemTableView.frame.size.height/self.menuItems.count];
    [self.menuItemTableView reloadData];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
.
.
.
    // Bad Apple! - http://stackoverflow.com/questions/2339721/hiding-a-uinavigationcontrollers-uitoolbar-during-viewwilldisappear
    [self.navigationController setToolbarHidden:YES animated:YES];
.
.
.
}
烧了回忆取暖 2024-08-29 21:07:59

管理工具栏状态(即哪个 VC 需要/不需要工具栏)很快就会变得棘手。

我已经成功地遵循了这条规则:

对于每个视图控制器,在 viewWillAppear() 中,决定它是否需要工具栏,然后调用 navigationController?.setToolbarHidden (true 或 false,animated:animated) 分别。

这样,每个视图控制器都会以正确的工具栏状态开始,并且您不必担心在视图时“恢复”工具栏状态。控制员被解雇。

Managing the toolbar state (i.e. which VC needs/doesn't need the toolbar) gets tricky quickly.

I've had success with following this rule:

For each view controller, in viewWillAppear(), decide if it needs a toolbar or doesn't, then call navigationController?.setToolbarHidden(true or false, animated: animated) respectively.

This way, each view controller starts out with the correct toolbar state and you don't have to worry about "restoring" the toolbar state when the view controller is dismissed.

魄砕の薆 2024-08-29 21:07:59

这只是在黑暗中进行的一次疯狂尝试,但也许您应该在隐藏工具栏后让运行循环运行一次:

[viewController setToolbarHidden:YES animated:YES];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0]];

This is just a wild stab in the dark but maybe you should let the runloop run once after hiding the toolbar:

[viewController setToolbarHidden:YES animated:YES];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0]];
秋日私语 2024-08-29 21:07:59

我遇到了同样的问题,这是对我有用的解决方案。假设您要将 SomeUIViewController 推送到导航堆栈上。

SomeUIViewController 的接口中定义这个(私有)ivar:

// keep a reference to the navigation controller for use in viewDidDisappear:(BOOL)animated method
UINavigationController * _navigationController; 

实现 SomeUIViewController 的以下方法:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // here, your controller still has a reference to self.navigationController
    _navigationController = [self.navigationController retain];
}

- (void)viewDidDisappear:(BOOL)animated {
    // at this point, self.navigationController = 0x0, so
    // use your retained reference to the navigation controller to perform any last minute operations, then release

    [_navigationController setToolbarHidden:YES];
    [_navigationController release];

    [super viewDidDisappear:animated];
}

这个想法是你想要隐藏导航控制器拥有的工具栏after SomeUIViewController 的视图消失了。这样,您就可以避免任何不需要的显示伪影。

免责声明

这只是一个答案,显示了所述问题的变通解决方案。它只是为了指出框架内部运作的细节。它还可以作为向 Apple AppStore 提交的示例。

I had the same problem and here is the solution that worked for me. Say you're pushing SomeUIViewController onto your navigation stack.

Define this (private) ivar in the interface of SomeUIViewController:

// keep a reference to the navigation controller for use in viewDidDisappear:(BOOL)animated method
UINavigationController * _navigationController; 

Implement the following methods of SomeUIViewController:

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    // here, your controller still has a reference to self.navigationController
    _navigationController = [self.navigationController retain];
}

- (void)viewDidDisappear:(BOOL)animated {
    // at this point, self.navigationController = 0x0, so
    // use your retained reference to the navigation controller to perform any last minute operations, then release

    [_navigationController setToolbarHidden:YES];
    [_navigationController release];

    [super viewDidDisappear:animated];
}

The idea is that you want to hide the toolbar owned by the navigation controller after SomeUIViewController's view has disappeared. This way, you avoid any unwanted display artifacts.

DISCLAIMER

This is merely an answer that shows a workaround solution for the stated question. It is meant solely to point out a detail of the inner workings of the framework. It is also meant as an example of what not to submit to the Apple AppStore.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文