7
votes

I have an ipad app where i would like to hide and show a category list (kind of like the small view in a split view controller), and the main view which contains a UiNavigationController stack.

I would like to resize the UINavigationController view to fill the whole screen when the category list is hidden, and to shrink when i show the list.

I have it working, except the title of the navigation bar immediately jumps to its new offset when setting the frame within an animation begin/commit block.

Any ideas how to stop the jump of the title?

4

4 Answers

3
votes

I used this for fixing those jumps in UINavigationBar for title and right button.

#import "UINavigationBar+My.h"

@implementation UINavigationBar (My)

- (void)layoutSubviews {
for (id obj in [self subviews]) {
    if ([NSStringFromClass([obj class]) isEqualToString:@"UINavigationItemView"])
        [(UIView *)obj setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin|UIViewAutoresizingFlexibleRightMargin];
    else if ([NSStringFromClass([obj class]) isEqualToString:@"UIButton"]) {
        if ([(UIButton *)obj center].x < ([self center].x / 2))
            [(UIButton *)obj setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
        else
            [(UIButton *)obj setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
    }
}

@end

I hope it will help you ;-)

2
votes

I ran into a similar problem recently; I had a subview of the animating view that was jumping immediately to its new position. This was happening because -layoutSubviews was being called on that view as a result of me programmatically modifying it before the animation finished. Are you doing something like changing the text of the title or modifying it in some way that would cause -layoutSubviews to be called on it?

1
votes

My solution, seems to cope with all scenarios I hit in my app. Obviously still a bit of a hack, so no guarantees it will always work!

@implementation UINavigationBar (Nick)

- (void)layoutSubviews {
    [super layoutSubviews];
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
        UIView* titleView = nil;
        CGFloat buttonWidths = 0;
        for (UIView* subview in [self subviews]) {

            if ([subview class] == NSClassFromString(@"UINavigationItemView")) {
                if (titleView) {
                    // Exit here - if there is more than one title, probably doing a pop
                    return;
                }
                titleView = subview;
            }
            else if ([subview class] == [UIView class] ||                           // bar button with custom view
                     [subview class] == NSClassFromString(@"UINavigationButton")) { // or ordinary bar button

                buttonWidths += subview.frame.size.width;
                // is it RHS?
                if (subview.frame.origin.x > subview.frame.size.width) {
                    [subview setAutoresizingMask:UIViewAutoresizingFlexibleLeftMargin];
                }
                else {
                    [subview setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
                }
            }
            else if ([subview class] == NSClassFromString(@"UINavigationItemButtonView")) {
                // pretty sure this is always the back button
                buttonWidths += subview.frame.size.width;
                [subview setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
            }
        }


        if (titleView) {
            buttonWidths += 20; // seems to be apple indentation
            CGRect rect = titleView.frame;
            if (rect.size.width > self.frame.size.width - buttonWidths) {
                rect.size.width = self.frame.size.width - buttonWidths;
                titleView.frame = rect;
            }

            titleView.center = self.center;
        }
    }
}
1
votes

It worked fine for me when I included [self.navigationController.navigationBar layoutSubviews] in the animation block itself. Here's the code example:

[UIView animateWithDuration:0.5
                 animations:^{
                     [self.navigationController.navigationBar setFrame:newFrame];
                     [self.navigationController.navigationBar layoutSubviews];
                 }];

I hope this is somehow helpful.