iOS: titleView панели навигации не изменяет размер правильно, когда телефон вращается - PullRequest
13 голосов
/ 14 января 2011

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

Но я назначаю пользовательское представление для navigationItem.titleView (область заголовка навигационной панели), и я не могу правильно изменить размер этого вида при повороте телефона.

Я знаю, о чем вы думаете, "Просто установите autoresizingMask в UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight, "но это не так просто.Конечно, если я не установлю свой вид autoresizingMask, тогда мой вид не изменится;и я хочу, чтобы он изменил размеры.

Проблема в том, что если я делаю установил его autoresizingMask, то он корректно изменяет размеры, пока этот вид виден;но размер titleView портится в этом сценарии:

  1. Запустите приложение, держа телефон в портретном режиме.Все выглядит хорошо.
  2. Сделайте что-нибудь, что заставит приложение выдвинуть другое представление в стек навигации.Например, щелкните строку таблицы или кнопку, которая вызывает вызов [self.navigationController pushViewController:someOtherViewController animated:YES].
  3. При просмотре дочернего контроллера поверните телефон в горизонтальное положение.
  4. Нажмите кнопку «Назад», чтобы вернуться квид на верхнем уровне.На этом этапе вид заголовка испорчен: хотя вы держите телефон в альбомном режиме, размер заголовка по-прежнему такой же, как если бы вы держали его в портретном режиме.
  5. Наконец, поверните телефон обратно впортретный режим.Теперь все становится еще хуже: размер заголовка уменьшается в размере (так как панель навигации стала меньше), но так как он был уже слишком маленьким, теперь он намного слишком мал.

Если вы хотите воспроизвести это самостоятельно, выполните следующие действия (это немного работы):

  1. Создайте приложение с помощью мастера Xcode «Приложение на основе навигации».
  2. Установитьтак, чтобы в табличном представлении верхнего уровня были строки, которые, когда вы щелкаете по ним, помещают подробный вид в стек навигации.
  3. Включите этот код как в контроллер представления верхнего уровня, так и вконтроллер подробного вида:

    - (BOOL)shouldAutorotateToInterfaceOrientation:
            (UIInterfaceOrientation)interfaceOrientation {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    }
    
  4. Включите этот код только в контроллер верхнего уровня:

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        // Create "Back" button
        UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Master"
            style:UIBarButtonItemStylePlain target:nil action:nil];
        self.navigationItem.backBarButtonItem = backButton;
        [backButton release];
    
        // Create title view
        UILabel* titleView = [[[UILabel alloc] initWithFrame:CGRectMake(0,0,500,38)] autorelease];
        titleView.textAlignment = UITextAlignmentCenter;
        titleView.text = @"Watch this title view";
    
        // If I leave the following line turned on, then resizing of the title view
        // messes up if I:
        //
        // 1. Start at the master view (which uses this title view) in portrait
        // 2. Navigate to the detail view
        // 3. Rotate the phone to landscape
        // 4. Navigate back to the master view
        // 5. Rotate the phone back to portrait
        //
        // On the other hand, if I remove the following line, then I get a different
        // problem: The title view doesn't resize as I want it to when I:
        //
        // 1. Start at the master view (which uses this title view) in portrait
        // 2. Rotate the phone to landscape
        titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    
        self.navigationItem.titleView = titleView;
    }
    
  5. Наконец, следуйте моемушаги репро.

Итак ... я что-то не так делаю?Есть ли способ, чтобы мой titleView всегда правильно изменял размер?

Ответы [ 7 ]

7 голосов
/ 14 декабря 2011

Вы также должны установить contentMode из UIImageView, чтобы правильно отобразить titleView в ландшафтном и / или портретном режиме:

imgView.contentMode=UIViewContentModeScaleAspectFit;

Вся последовательность: (self это UIViewController экземпляр)

UIImageView* imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"myCustomTitle.png"]];
imgView.autoresizingMask=UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
imgView.contentMode=UIViewContentModeScaleAspectFit;
self.navigationItem.titleView = imgView;
[imgView release];
4 голосов
/ 14 января 2011

У меня было что-то похожее - но оно возвращалось (всплывающее) к корневому контроллеру представления.В конечном итоге я выбрал следующее:

[[self navigationController] setNavigationBarHidden:YES animated:NO];
[[self navigationController] popViewControllerAnimated:YES];
[[self navigationController] setNavigationBarHidden:NO animated:NO];

И это сработало.Возможно, был и лучший способ, но - после всех часов, которые я уже потратил на эту проблему, - этого было достаточно для меня.

3 голосов
/ 25 октября 2011

Я имел дело с этой же проблемой, отслеживая начальный кадр customView, затем переключаясь между ним и масштабированным CGRect начального кадра в методе -setLandscape подкласса UIButton. Я использовал подкласс UIButton как navigationItem.titleView и navigationItem.rightBarButtonItem.

В подклассе UIButton -

- (void)setLandscape:(BOOL)value
 {
     isLandscape = value;

     CGFloat navbarPortraitHeight = 44;
     CGFloat navbarLandscapeHeight = 32;

     CGRect initialFrame = // your initial frame
     CGFloat scaleFactor = floorf((navbarLandscapeHeight/navbarPortraitHeight) * 100) / 100;

     if (isLandscape) {
         self.frame = CGRectApplyAffineTransform(initialFrame, CGAffineTransformMakeScale(scaleFactor, scaleFactor));
     } else {
         self.frame = initialFrame;
     }
 }

Затем в делегатах InterfaceOrientation я вызвал метод -setLandscape в пользовательских окнах, чтобы изменить их размеры.

В UIViewController -

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{
    [self updateNavbarButtonsToDeviceOrientation];;
}

- (void)updateNavbarButtonsToDeviceOrientation
 {
     ResizeButton *rightButton = (ResizeButton *)self.navigationItem.rightBarButtonItem.customView;
     ResizeButton *titleView = (ResizeButton *)self.navigationItem.titleView;

     if (self.interfaceOrientation == UIDeviceOrientationPortrait || self.interfaceOrientation == UIDeviceOrientationPortraitUpsideDown) {
         [rightButton setLandscape:NO];
         [titleView setLandscape:NO];
     } else {
         [rightButton setLandscape:YES];  
         [titleView setLandscape:YES];
     }
 }
2 голосов
/ 30 апреля 2013

Для IOS5 и выше, так как это старый вопрос ... Вот как я выполнил ту же проблему с текстом заголовка, не выровненным должным образом

[[UINavigationBar appearance] setTitleVerticalPositionAdjustment:2 forBarMetrics:UIBarMetricsLandscapePhone];

Протестировано на ios5 / 6 sims работает нормально.

2 голосов
/ 09 июня 2011

(отвечая на мой вопрос)

Я получил эту работу, вручную отслеживая поля titleView (его расстояние от краев панели навигации) - сохраняя при исчезновении представления, и восстанавливая при повторном появлении представления.

Идея в том, что мы не восстанавливаем titleView до того размера, который у него был ранее; скорее, мы восстанавливаем его так, чтобы оно имело те же поля , что и ранее. Таким образом, если телефон повернут, titleView будет иметь новый, соответствующий размер.

Вот мой код:

В моем представлении .h файл контроллера:

@interface MyViewController ...
{
    CGRect titleSuperviewBounds;
    UIEdgeInsets titleViewMargins;
}

В моем представлении .m файл контроллера:

/**
 * Helper function: Given a parent view's bounds and a child view's frame,
 * calculate the margins of the child view.
 */
- (UIEdgeInsets) calcMarginsFromParentBounds:(CGRect)parentBounds
                                  childFrame:(CGRect)childFrame {
    UIEdgeInsets margins;
    margins.left = childFrame.origin.x;
    margins.top = childFrame.origin.y;
    margins.right = parentBounds.size.width -
        (childFrame.origin.x + childFrame.size.width);
    margins.bottom = parentBounds.size.height -
        (childFrame.origin.y + childFrame.size.height);
    return margins;
}

- (void)viewDidUnload {
    [super viewDidUnload];

    titleSuperviewBounds = CGRectZero;
    titleViewMargins = UIEdgeInsetsZero;
}

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

    // Keep track of bounds information, so that if the user changes the
    // phone's orientation while we are in a different view, then when we
    // return to this view, we can fix the titleView's size.
    titleSuperviewBounds = self.navigationItem.titleView.superview.bounds;
    CGRect titleViewFrame = self.navigationItem.titleView.frame;
    titleViewMargins = [self calcMarginsFromParentBounds:titleSuperviewBounds
                                              childFrame:titleViewFrame];
}


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

    // Check for the case where the user went into a different view, then
    // changed the phone's orientation, then returned to this view.  In that
    // case, our titleView probably has the wrong size, and we need to fix it.
    if (titleSuperviewBounds.size.width > 0) {
        CGRect newSuperviewBounds =
            self.navigationItem.titleView.superview.bounds;
        if (newSuperviewBounds.size.width > 0 &&
            !CGRectEqualToRect(titleSuperviewBounds, newSuperviewBounds))
        {
            CGRect newFrame = UIEdgeInsetsInsetRect(newSuperviewBounds,
                titleViewMargins);
            newFrame.size.height =
                self.navigationItem.titleView.frame.size.height;
            newFrame.origin.y = floor((newSuperviewBounds.size.height -
                self.navigationItem.titleView.frame.size.height) / 2);
            self.navigationItem.titleView.frame = newFrame;
        }
    }
}
1 голос
/ 05 мая 2013

Это то, что я сделал:

self.viewTitle.frame = self.navigationController.navigationBar.frame;
self.navigationItem.titleView = self.viewTitle;

viewTitle - это представление, созданное в xib, оно принимает размер панели навигации и после того, как было добавлено titleView, отрегулируйте размер, чтобы оставить место длякнопка назад.Вращения вроде бы работают нормально.

0 голосов
/ 17 марта 2011

У меня была такая же проблема, но мне кажется, что я могу обойти следующий код.

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

    UIView *urlField = self.navigationItem.leftBarButtonItem.customView;
    CGRect frame = urlField.frame;
    frame.size.width = 1000;
    urlField.frame = frame;
}

В моем случае пользовательское представление - это UITextField, но я надеюсь, что это поможет вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...