2011-01-14 9 views
13

Ich schreibe eine iPhone-App, die (wie die meisten Apps) die automatische Drehung unterstützt: Sie drehen Ihr Telefon, und seine Ansichten werden entsprechend gedreht und skaliert.iOS: Titelansicht der Navigationsleiste ändert sich nicht richtig, wenn das Telefon rotiert

Aber ich eine benutzerdefinierte Ansicht zu navigationItem.titleView zuweisen (der Titelbereich der Navigationsleiste), und ich kann nicht erhalten, dass die Ansicht korrekt zu ändern, wenn das Telefon rotiert.

Ich weiß, was Sie denken, "Setzen Sie einfach autoresizingMask auf UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight," aber es ist nicht so einfach. Natürlich, wenn ich nicht die autoresizingMask Ansicht meiner Ansicht festlegen, ändert meine Ansicht nicht die Größe; und ich möchte, dass sich die Größe ändert.

Das Problem ist, wenn ich tun setze autoresizingMask, dann ändert sich die Größe korrekt, solange diese Ansicht sichtbar ist; aber die titleView 's Größe wird in diesem Szenario versaut:

  1. Führen Sie die App, mit dem Telefon im Hochformat gehalten. Alles sieht gut aus.
  2. Machen Sie etwas, was dazu führt, dass die App eine andere Ansicht auf den Navigationsstapel verschiebt. Z.B. Klicken Sie auf eine Tabellenzeile oder eine Schaltfläche, die einen Aufruf an [self.navigationController pushViewController:someOtherViewController animated:YES] verursacht.
  3. Während Sie den Kindercontroller anzeigen, drehen Sie das Telefon auf Querformat.
  4. Klicken Sie auf die Schaltfläche "Zurück", um zur Ansicht auf oberster Ebene zurückzukehren. An dieser Stelle ist die Titelansicht durcheinander: Obwohl Sie das Telefon im Querformat halten, ist die Titelansicht immer noch so groß, als ob Sie sie im Hochformat halten würden.
  5. Schließlich, drehen Sie das Telefon zurück in den Hochformat-Modus. Jetzt wird es noch schlimmer: Die Titelansicht verkleinert sich (seit die Navigationsleiste kleiner geworden ist), aber da es schon zu klein war, ist es nun viel zu klein.

Wenn Sie diese Texte selbst reproduzieren möchten, gehen Sie folgendermaßen vor (dies ist ein wenig Arbeit):

  1. eine App Make Xcode „Navigation-basierte Anwendung“ Assistenten.
  2. Richten Sie es so ein, dass die Tabellenansicht der obersten Ebene über Zeilen verfügt, die beim Klicken auf eine Detailansicht auf den Navigationsstapel übertragen werden.
  3. Fügen Sie diesen Code sowohl in der Top-Level-View-Controller und der Detailansicht Controller:

    - (BOOL)shouldAutorotateToInterfaceOrientation: 
         (UIInterfaceOrientation)interfaceOrientation { 
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); 
    } 
    
  4. diesen Code Fügen Sie nur in der Top-Level-View-Controller:

    - (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. Schließlich Folge meinen Reproschritten.

Also ... mache ich etwas falsch? Gibt es eine Möglichkeit, meine Titelansicht immer korrekt zu skalieren?

Antwort

2

(Beantwortung meiner Frage)

ich diese Arbeit bekam durch manuelles der Titleview Margen (ihr Abstand von den Rändern der navigtion bar) zu verfolgen - Speichern, wenn die Ansicht verschwindet, und die Wiederherstellung, wenn die Ansicht erscheint wieder.

Die Idee ist, dass wir die titleView nicht auf die exakte Größe wiederherstellen, die sie vorher hatte; Stattdessen stellen wir es wieder her, so dass es die gleichen Ränder es zuvor hatte. Wenn das Telefon gedreht wurde, hat die Titelansicht eine neue, passende Größe.

Hier ist mein Code:

Meiner Ansicht .h-Datei des Controllers:

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

Meiner Ansicht .m-Datei des Controllers:

/** 
* 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

Nahm deinen Code genau und es funktioniert gut für mich, danke! – esilver

+0

Ich könnte zu spät sein (4-5 Jahre lol), aber darf ich fragen ... in AutoLayout ... passiert Ihnen das "nicht skalierende" Zeug immer noch? Ich arbeite mit Storyboards und UINavigationControllern, wenn ich einen wirklich langen Titel anlege (sagen wir mal 100 Zeichen oder mehr), wenn das iPhone gedreht wird, funktioniert es gut, aber irgendwann behält es die Landschaftsgröße für die Titelansicht bei zum Hochformat gedreht Ich weiß nicht, was ich machen soll. Ohne Personalisierung (Ziehen von Navcontroller + Root View Controller ohne benutzerdefinierte Klassen) geschieht dies immer noch. Es macht mich verrückt, sieht aus wie ein iOS-Bug ... –

3

Ich hatte etwas Ähnliches - aber es kehrte zum Root-View-Controller zurück (knallte). Schließlich ging ich mit den folgenden für knallen:

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

Und es funktionierte.Es mag einen besseren Weg gegeben haben, aber - nach all den Stunden, die ich schon für dieses Thema ausgegeben hatte - das war gut genug für mich.

0

Ich hatte das gleiche Problem, aber ich habe mit folgendem Code Abhilfe zu bekommen.

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

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

In meinem Fall ist die benutzerdefinierte Ansicht ein UITextField, aber ich hoffe, dies wird Ihnen helfen.

3

ich mit dem gleichen Problem behandelt durch Verfolgen des ursprünglichen Frames von customView, dann Umschalten zwischen diesem und einem skalierten CGRect des ursprünglichen Frames in einer -setLandscape-Methode für eine UIButton-Unterklasse. Ich habe die UIButton-Unterklasse als navigationItem.titleView und navigationItem.rightBarButtonItem verwendet.

In UIButton Unterklasse -

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

Dann in den InterfaceOrientation Delegierten aufgerufen ich die -setLandscape Methode auf der Custom ihre Größe zu ändern.

In 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

Sie auch die contentMode der UIImageView gesetzt soll die titleView richtig angezeigt in Landschaft und/oder Portrait-Modus zu erhalten:

imgView.contentMode=UIViewContentModeScaleAspectFit;

die gesamte Sequenz: (Selbst ist eine UIViewController Instanz)

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

Für IOS5, da dies eine alte Frage ist ... So habe ich das gleiche Problem mit dem Titel Text nicht richtig ausgerichtet.

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

Getestet auf ios5/6 sims funktioniert gut.

+0

Diese einzige Zeile löste mein Problem.Perfekt für iOS 5+ – LightMan

1

Das ist, was ich tat:

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

Die viewTitle eine Ansicht in xib erstellt ist, ist es die Größe des navigationbar nimmt und, nachdem er die Titleview anzupassen hinzugefügt wurde, um die Größe Raum, zu gehen Zurück-Button. Drehungen scheinen gut zu funktionieren.

Verwandte Themen