2011-01-14 34 views
13

Tôi đang viết một ứng dụng iPhone (giống như hầu hết các ứng dụng) hỗ trợ xoay tự động: Bạn xoay điện thoại của mình và chế độ xem xoay vòng và thay đổi kích thước phù hợp.iOS: Tiêu đề của thanh điều hướng không thay đổi kích thước chính xác khi điện thoại quay

Nhưng tôi chỉ định chế độ xem tùy chỉnh cho navigationItem.titleView (vùng tiêu đề của thanh điều hướng) và tôi không thể làm cho chế độ xem đó đổi kích thước chính xác khi điện thoại xoay.

Tôi biết bạn đang nghĩ gì, "Chỉ cần đặt autoresizingMask thành UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight", nhưng nó không đơn giản như vậy. Tất nhiên, nếu tôi không đặt chế độ xem của tôi là autoresizingMask thì chế độ xem của tôi không thay đổi kích thước; và tôi muốn nó đổi kích thước.

Vấn đề là, nếu tôi làm đặt autoresizingMask, sau đó thay đổi kích thước chính xác miễn là chế độ xem đó hiển thị; nhưng kích thước của titleView bị rối loạn trong trường hợp này:

  1. Chạy ứng dụng, với điện thoại được giữ ở chế độ dọc. Mọi thứ trông có vẻ tốt.
  2. Làm điều gì đó khiến ứng dụng đẩy chế độ xem khác lên ngăn điều hướng. Ví dụ. nhấp vào một hàng hoặc nút của bảng có chức năng gọi đến [self.navigationController pushViewController:someOtherViewController animated:YES].
  3. Trong khi xem bộ điều khiển con, xoay điện thoại sang ngang.
  4. Nhấp vào nút "Quay lại" để quay lại chế độ xem cấp cao nhất. Tại thời điểm này, chế độ xem tiêu đề bị rối loạn: Mặc dù bạn đang cầm điện thoại ở chế độ ngang, chế độ xem tiêu đề vẫn có kích thước như thể bạn đang cầm nó ở chế độ dọc.
  5. Cuối cùng, xoay điện thoại trở lại chế độ dọc. Bây giờ mọi thứ trở nên tồi tệ hơn: Chế độ xem tiêu đề co lại theo kích thước (vì thanh điều hướng trở nên nhỏ hơn), nhưng vì nó đã quá nhỏ nên giờ là nhiều quá nhỏ.

Nếu bạn muốn tái sản xuất này cho mình, hãy làm theo các bước sau (đây là một chút công việc):

  1. Hãy một ứng dụng sử dụng Xcode của "Navigation dựa trên ứng dụng" wizard.
  2. Thiết lập để chế độ xem bảng cấp cao nhất có các hàng, khi bạn nhấp vào chúng, hãy đẩy chế độ xem chi tiết vào ngăn điều hướng.
  3. Bao gồm mã này trong cả hai bộ điều khiển xem cấp cao nhất và bộ điều khiển xem chi tiết:

    - (BOOL)shouldAutorotateToInterfaceOrientation: 
         (UIInterfaceOrientation)interfaceOrientation { 
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 
    } 
    
  4. Bao gồm mã này chỉ trong bộ điều khiển xem top-level:

    - (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. Cuối cùng , hãy làm theo các bước repro của tôi.

Vì vậy, tôi đang làm điều gì đó sai? Có cách nào để làm cho titleView của tôi luôn thay đổi kích thước chính xác không?

Trả lời

2

(Trả lời câu hỏi của riêng tôi)

tôi đã làm việc này bằng cách thủ công theo dõi các lề của titleView (khoảng cách của nó từ mép của thanh navigtion) - tiết kiệm khi xem biến mất, và khôi phục lại khi xem xuất hiện trở lại.

Ý tưởng là, chúng tôi không khôi phục tiêu đềView thành kích thước chính xác trước đây; thay vào đó, chúng tôi đang khôi phục nó để có cùng một lợi nhuận tương tự trước đây. Bằng cách đó, nếu điện thoại đã xoay, tiêu đềView sẽ có kích thước mới phù hợp.

Đây là mã của tôi:

Trong file .h điều khiển quan điểm của tôi:

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

Trong file .m điều khiển quan điểm của tôi:

/** 
* 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; 
     } 
    } 
} 
+0

Lấy mã của bạn chính xác và nó hoạt động tuyệt vời cho tôi, cảm ơn! – esilver

+0

Tôi có thể đã quá trễ (4-5 năm lol), nhưng tôi có thể yêu cầu ... trong AutoLayout ... điều này "không thay đổi kích thước" công cụ vẫn xảy ra với bạn? Tôi đang làm việc với Storyboards và UINavigationControllers, khi tôi đặt tiêu đề thực sự dài (cho phép nói ... 100 ký tự trở lên), khi xoay iPhone, nó hoạt động tốt nhưng tại một thời điểm nó đơn giản giữ kích thước ngang cho chế độ xem tiêu đề khi được xoay sang dọc. Tôi không biết phải làm gì. Nếu không có cá nhân hóa (kéo Navcontroller + Root xem bộ điều khiển mà không có các lớp tùy chỉnh) điều này vẫn còn xảy ra. Điều đó khiến tôi phát điên, trông giống như lỗi iOS ... –

3

Tôi đã có một cái gì đó tương tự - nhưng nó đã trở lại (popping) để kiểm soát xem gốc. Cuối cùng, tôi đã thực hiện các bước sau cho popping:

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

Và nó hoạt động.Có thể có một cách tốt hơn nhưng - sau tất cả những giờ tôi đã dành cho vấn đề này - điều này là đủ tốt cho tôi.

0

Tôi đã gặp sự cố tương tự, nhưng dường như tôi gặp phải vấn đề với mã sau đây.

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

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

Trong trường hợp của tôi, chế độ xem tùy chỉnh là UITextField, nhưng tôi hy vọng điều này sẽ giúp bạn.

3

tôi giải quyết vấn đề này cùng bởi theo dõi khung ban đầu của customView, sau đó chuyển đổi giữa khung hình đó và CGRect được chia tỷ lệ của khung ban đầu trong phương thức -setLandscape trên lớp con UIButton. Tôi đã sử dụng lớp con UIButton như navigationItem.titleView và navigationItem.rightBarButtonItem.

Trong UIButton lớp con -

- (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; 
    } 
} 

Sau đó, trong các đại biểu InterfaceOrientation Tôi gọi phương pháp -setLandscape trên customViews để thay đổi kích thước của chúng.

Trong 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]; 
    } 
} 
7

Bạn cũng nên thiết lập các contentMode của UIImageView để có được những titleView hiển thị đúng trong cảnh quan và/hoặc chế độ chân dung:

imgView.contentMode=UIViewContentModeScaleAspectFit;

Toàn bộ trình tự: (tự là một ví dụ UIViewController)

UIImageView* imgView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"myCustomTitle.png"]]; 
imgView.autoresizingMask=UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 
imgView.contentMode=UIViewContentModeScaleAspectFit; 
self.navigationItem.titleView = imgView; 
[imgView release]; 
2

Đối với IOS5 trở đi, vì đây là câu hỏi cũ ... Đây là cách tôi hoàn thành cùng một vấn đề với văn bản tiêu đề không căn chỉnh đúng cách.

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

Thử nghiệm trên ios5/6 sims hoạt động tốt.

+0

Dòng đơn này đã giải quyết được sự cố của tôi.Hoàn toàn cho iOS 5+ – LightMan

1

Đây là những gì tôi đã làm:

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

Các viewTitle là một cái nhìn tạo ra trong xib, phải mất kích thước của Navigationbar và sau khi nó đã được thêm vào các titleView điều chỉnh kích thước để rời khỏi phòng đến nút quay lại. Xoay dường như hoạt động tốt.

Các vấn đề liên quan