2010-09-10 10 views
27

Ich habe festgestellt, dass die Position von titleView vom Titel der rechten Maustaste abhängt. Wie kann ich den Rahmen der Titelansicht stattdessen in der Mitte festlegen?Den Rahmen von navigationItem.titleView anpassen?

Ich habe versucht, titleView.frame zu setzen, aber ohne Erfolg.

Hier ist der Code:

UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom]; 
[titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal]; 
[titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 
[titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted]; 
titleLabel.frame = CGRectMake(100, 0, 180, 44); 
titleLabel.titleLabel.backgroundColor = [UIColor clearColor]; 
titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0]; 
titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3]; 
// titleLabel.titleLabel.textAlignment = UITextAlignmentCenter; (this doesn't work either) 
[titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside]; 
self.navigationItem.titleView = titleLabel; 
self.navigationItem.titleView.frame = CGRectMake(100, 0, 180, 44); //(this doesn't work either) 

alt text

+0

anyone? jemand Hilfe! –

+0

Ich habe das gleiche Problem! Buttons auf der linken oder rechten Seite bewirken, dass die Titelansicht erneut zentriert wird, auch nachdem ich sie genau in layoutSubviews gesetzt habe. – quantumpotato

Antwort

46

Irgendwann zwischen dem viewWillAppear Ihres View-Controllers: & viewDidAppear: Die Navigationsleiste positioniert Ihre titleView neu und passt sie bei Bedarf an. Es kann unzensiert enden, weil die Navigationsleiste es vorzieht, die Titelansicht nicht so anzupassen, dass sie zwischen die Schaltflächen passt. Es scheint zu versuchen, die Titelansicht zu zentrieren, wenn es klein genug ist, aber wenn nicht, wird deine Titelansicht außermittig verschoben, und dann denke ich, dass nur als letztes Mittel die Größe geändert wird. Der Effekt ist, dass die Titelansicht den gesamten Abstand zwischen den beiden Schaltflächen einnimmt, wenn ihre Textausrichtung zentriert ist, wird sie in der Mitte zentriert, jedoch nicht zentriert in Bezug auf den gesamten Bildschirm. Sie können dies in Ihrem Screenshot sehen.

Eine Antwort ist, dass Sie Ihre Titelansicht schmaler machen, damit die Navigationsleiste sie zentrieren kann. Versuchen Sie also, wenn Sie Ihren TitelView.frame festlegen, etwa 160 statt 180. Es saugt, dass, wenn Sie die Ansicht programmatisch wie Sie erstellen, eine Schätzung für diese Breite in den Code eingeben muss. Was gut wäre, ist eine Möglichkeit, diesen Raum zu maximieren, während er zentriert bleibt.

Es ist möglich, mit der titleView zu beginnen, die die Bildschirmbreite ist, dann, nachdem die Navigationsleiste titleView.frame ändert, aktualisieren Sie es wieder selbst in der Ansicht des Viewers viewDidAppear :. Mit den angepassten Titeln "View.frame.origin.x" und "size.width" zusammen mit der Bildschirmbreite können Sie den größten der linken rechten Ränder berechnen und dann den Wert von "origin.x" auf die Größe "width.width" auf die Bildschirmbreite einstellen das mal 2. Das wird aber erst wirksam, nachdem die gedrückte Ansicht animiert wurde und die Verschiebung danach sichtbar ist. Sie könnten die titleView in viewWillAppear verbergen: dann in viewDidAppear einblenden: nachdem Sie es zentriert haben, wird es statt mit einer exzentrischen titleView, die dann verschoben wird, hineingleiten ohne einen Titel, der dann erscheint.

Eine bessere Möglichkeit besteht darin, Ihre titleView Ihre eigene Unterklasse von UIView (oder UILabel oder whichver) zu machen und setFrame zu überschreiben, um die Größe zu ändern, um in seiner Superansicht zentriert zu bleiben. Wenn ich das jemals selbst mache, poste ich es hier. Oder vielleicht kennt jemand anders einen anderen Ort, um den Rahmen von titleView zu ändern, nachdem er aktualisiert wurde, aber bevor die Ansicht ohne eine Unterklasse der Ansicht eingeblendet wird.

+2

Das sollte wirklich als Antwort markiert werden. Dadurch habe ich die Breite meiner Ansicht genau so eingestellt, wie es für den Text in meinem Etikett erforderlich war. Das hat super funktioniert! – GendoIkari

+0

Danke für das Schreiben dieser Antwort, es hat mir sehr geholfen. –

+0

Ich habe eine Beobachtung über die Frame-Eigenschaft von navigationBar gemacht und habe getan, was Sie vorgeschlagen haben, als sich der Frame von navigationBar änderte. In meinem Fall ist das Problem bei Orientierungsänderungen aufgetreten. –

0

Das gleiche Problem hier. AutoScrolling Label als TitelView implementieren. So kann lange Text im Navigationstitel automatisch gescrollt werden, damit der Benutzer alles sehen kann. All diese Probleme mit unbekannten realen Dimensionen von titleView verhindern die Textzentrierung im einfachsten Fall: wenn Labeltext passt und keine Autoscrolling benötigt wird (wie das Setzen von Text in die title-Eigenschaft von navigationItem).

1
-(void) awakeFromNib 
{ 
    UIButton *titleLabel = [UIButton buttonWithType:UIButtonTypeCustom]; 
    [titleLabel setTitle:@"Right Eye" forState:UIControlStateNormal]; 
    [titleLabel setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 
    [titleLabel setTitleColor:[UIColor blackColor] forState:UIControlStateHighlighted]; 
    titleLabel.titleLabel.backgroundColor = [UIColor clearColor]; 
    titleLabel.titleLabel.font = [UIFont boldSystemFontOfSize:20.0]; 
    titleLabel.titleLabel.shadowColor = [UIColor colorWithWhite:0.0 alpha:0.3]; 
    [titleLabel addTarget:self action:@selector(titleTap:) forControlEvents:UIControlEventTouchUpInside]; 
    titleLabel.frame = CGRectMake(0, 0, 400, 20); 
    self.navigationItem.titleView = titleLabel; 

} 
+1

Bitte rufen Sie Release nicht auf einem Autorelease-Objekt ... – Lolloz89

17

nach dem Titleview oder Titlelabel einrichten, sizeToFit auf ihn nennen, auch sicher titleLabel.textAlignment = UITextAlignmentCenter machen. Es wird in der Breite der Navigationsleiste zentriert und nicht in dem Abstand zwischen der Schaltflächenkante und der entfernten Kante der Navigationsleiste.

+1

das einfach funktioniert. Als ich die Antwort zum ersten Mal gelesen habe, habe ich die lange "unmögliche" Antwort gelesen und fürchte mich ein bisschen. Dies sollte als richtig markiert werden. – shem

+0

Das funktioniert ganz gut. Es funktioniert auch auf anderen UIViews wie UIButton. –

12

Keiner der Vorschläge hier funktionierte wirklich für mich.Mein Problem war, dass ich titleView einstellte, während sich die Navigationsleiste mitten in der Transition befand - ich würde diesen merkwürdigen Jitter bekommen, wo die titleView nach links flackern würde und dann wieder in der Mitte landen würde.

endete ich folgende smallduck Idee und übergeordnete SetFrame, war so einfach wie:

- (void)viewDidAppear 
{ 
    [super viewDidAppear]; 
    [self.navigationController.navigationBar setFrame:CGRectMake(x, y, width, height)]; 
} 

... danach:

- (void)setFrame:(CGRect)frame { 
    [super setFrame:CGRectMake(0, 0, self.superview.bounds.size.width, self.superview.bounds.size.height)]; 
} 
+0

hat sofort funktioniert! –

1

Meine Lösung manuell die Navigationsleiste in viewDidAppear die Größe war Sie können die Titelansicht auch neu positionieren. Ich habe gerade gemerkt, dass das Hauptproblem darin bestand, dass die Navigationsleiste ebenfalls verkleinert wurde, also habe ich sie auf ihre normale Größe gebracht. Ich habe die normale Größe von Debuggen und Überprüfen der Größe in ViewDidLoad, bevor es geändert wurde ...

+0

Nicht eine gute Option Option –

+0

Dies war die nächste Lösung, die für mich funktionierte. Ich musste eine switch-Anweisung basierend auf dem Button-Bild machen, das je nach dem, was der Benutzer ausgewählt hat, variieren könnte. Ich habe die Informationen vom Debugger über die Größe genommen und entsprechend angepasst. – invertedfjord

6

Sie können versuchen, den Rahmen zu CGRectZero zunächst festlegen und sizeToFit aufrufen. Unten ist der Code, den ich verwendet habe, um den Titeltext zu ändern und sicherzustellen, dass er immer noch zentriert ist. Ich hatte einen Zurück-Knopf auf der linken Seite.

UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero];  
label.text = @"Title"; 
[label sizeToFit]; 
self.navigationItem.titleView = label; 
+0

anstatt Frame auf CGRectZero zu setzen, können Sie einfach 'UILabel * label = [[UILabel alloc] init];' –

0

Ich habe einen etwas anderen Anwendungsfall (vertikaler Offset von UIButton als titleView auf iOS 7). Nach einer langen Zeit kam ich mit der contentEdgeInsets Eigenschaft der UIButton, um den Inhalt in seinem Rahmen zu verschieben.

0

Das einzige, was ich gefunden habe, um das zu beheben, ist, UINavigationItems nicht zu verwenden. Insted verwenden zwei verschiedene Ansichten auf eace Taste Seite des UINavigationBar wie so:

-(UIView *)rightButtonViewSection { 
    if (!_rightButtonViewSection) { 

     _rightButtonViewSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 45)]; 

    } 
    return _rightButtonViewSection; 

} 

-(UIView *)leftButtonViewSection { 
    if (!_leftButtonViewSection) { 

     _leftButtonViewSection = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 80, 45)]; 

    } 
    return _leftButtonViewSection; 

} 

und setButtons auf es etwa so:

ButtonBase *searchButton = [[ButtonBase alloc] initWithFrame:CGRectMake(0, 0, 32, 30)]; 
    [searchButton setImage:[UIImage imageNamed:SEARCH_IMAGE] forState:UIControlStateNormal]; 
    SEL searchSelector = @selector(tradersSearchButtonPress); 
    [searchButton addTarget:self action:searchSelector forControlEvents:UIControlEventTouchUpInside]; 

    self.notificationButton.view.frame = [self rightButtonFrame]; 
    searchButton.frame = [self rightSecoundButtonFrame]; 

    [self.rightButtonViewSection removeAllSubviews]; 
    [self.rightButtonViewSection addSubview:self.notificationButton.view]; 
    [self.rightButtonViewSection addSubview:searchButton]; 

    UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithCustomView:self.rightButtonViewSection]; 
    self.topViewController.navigationItem.rightBarButtonItem = buttonItem; 

ButtonsFrames:

-(CGRect) rightButtonFrame { 
    return CGRectMake(self.rightButtonViewSection.width - 32, 7, 32, 30); 
} 
-(CGRect) rightSecoundButtonFrame { 
    return CGRectMake(self.rightButtonViewSection.width - 80, 7, 32, 30); 
} 

Dann wird der Titel nicht bewegen! weil die UIButtonsViews die gleiche Breite haben.

-1

Nur unsichtbare Schaltfläche hinzufügen (kein Text) auf dem rechten Seite der Navigationsleiste und Größe zum Beispiel 20 Pixel ändern

0

ich einen zweireihigen Titels ähnlich wie etwas Umsetzung WhatsApp tut (Titel und Untertitel) .

Ich behob dieses Problem durch Unterklassen UINavigationController und überschreiben viewDidLayoutSubviews().

sieht My Titleview wie folgt aus (in einem viewController):

let frame = self.navigationController?.navigationBar.bounds ?? CGRect.zero 

// This is a container view for the two labels, laying them out vertically 
let titleView = UIStackView(arrangedSubviews: [self._titleLabel, self._promptLabel]) 
titleView.axis = .vertical 
titleView.alignment = .center 
titleView.distribution = .fill 
titleView.frame = frame // set the frame to the navbarFrame initially 
titleView.spacing = 0 

// The wrapper is necessary for laying out the stackView as the titleView 
let wrapperView = UIView(frame: frame) 
wrapperView.addSubview(titleView) 

self.navigationItem.titleView = wrapperView 

Mein viewDidLayoutSubviews():

guard let navigationItem = self.topViewController?.navigationItem, 
     let titleView = navigationItem.titleView, 
     let wrapperView = titleView.subviews[0] as? UIStackView else { return } 

var width : CGFloat = 0 

for view in wrapperView.arrangedSubviews { 
    view.sizeToFit() 
    width = max(width, view.frame.size.width) 
} 

titleView.frame.size.width = width 
titleView.frame.size.height = self.navigationBar.frame.height 
wrapperView.frame = titleView.bounds 
wrapperView.center.x = self.navigationBar.convert(self.navigationBar.center, to: titleView).x 
wrapperView.center.y = titleView.frame.height/2 

self.navigationBar.layoutIfNeeded() 

Hinweis: Der Trick ist, eine Wrapper-Ansicht um Ihre Titleview zu haben, die kann über die Navigationsleiste angelegt werden. Passen Sie dann den Rahmen Ihrer Titelansicht an, was Sie wünschen.

0

Vor kurzem habe ich mit dem gleichen Problem konfrontiert, ich habe eine komplexe Titelansicht, deren Inhalt ändert sich, so dass ich so mehr Inhalt wie möglich zeigen kann, hat meine linke Leiste Schaltfläche Element und rechte Leiste Schaltfläche Element hat unterschiedliche Breite, also wenn Ich stelle es auf eine lange Breite ein, die Navigationsleiste zentriert es nicht. Wie Sie vielleicht wissen, wenn der linke oder rechte Balkenknopf sehr lang ist, ist es unmöglich, die Titelansicht zu zentrieren, deshalb möchte ich sie so weit wie möglich zentrieren.

Sobald wir eine Ansicht auf self.navigationItem.titleView eingestellt haben, wird die Navigationsleiste den Rahmen der Titelansicht verwalten, es ist schwer, sie direkt zu zentrieren, so dass ich eine Ansicht abtrenne, die als Containeransicht der echten Titelansicht funktioniert width, UINavigationBar mit seinem Rahmen auf einen Eigenschaftswert bezüglich seines linken/rechten Balkenknopfelements.

Der Behälter Ansicht ist MDLNavigationTitleContainer und die eigentliche Titelansicht ist MDLMessagesNavigationTitleView, MDLMessagesNavigationTitleView durch Auto-Layout verwaltet wird, wie es super Ansicht ist, ist MDLNavigationTitleContainer, wird jedes Mal, seine Breite ändert, layoutSubviews aufgerufen werden. Der Code in layoutSubviews scheint ein wenig seltsam, es wird verwendet, um die Push/Pop-Animation zu behandeln.

@interface MDLNavigationTitleContainer() 

@property (nonatomic) CGRect oldFrame; 

@end 

@implementation MDLNavigationTitleContainer 

- (instancetype)initWithFrame:(CGRect)frame { 
    self = [super initWithFrame:frame]; 
    if (self) { 
     UINib *nib = [UINib nibWithNibName:@"MDLMessagesNavigationTitleView" bundle:[NSBundle bundleForClass:[MDLMessagesNavigationTitleView class]]]; 
     self.titleView = [[nib instantiateWithOwner:nil options:nil] firstObject]; 
     self.titleView.translatesAutoresizingMaskIntoConstraints = NO; 
     [self addSubview:self.titleView]; 
     NSLayoutConstraint *centerX = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; 
     NSLayoutConstraint *centerY = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; 
     NSLayoutConstraint *width = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:0]; 
     width.priority = 200; 
     NSLayoutConstraint *width1 = [NSLayoutConstraint constraintWithItem:self.titleView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeWidth multiplier:1 constant:0]; 
     [self addConstraint:centerX]; 
     [self addConstraint:centerY]; 
     [self addConstraint:width]; 
     [self addConstraint:width1]; 
    } 
    return self; 
} 

- (void)layoutSubviews { 
    [super layoutSubviews]; 

    if (!self.superview) { 
     return; 
    } 

    if (self.center.x > [UIScreen mainScreen].bounds.size.width) { 
     self.titleView.frame = self.oldFrame; 
     return; 
    } 

    CGFloat centerX = self.center.x; 

    CGFloat superWidth = [UIScreen mainScreen].bounds.size.width; 
    CGFloat superCenterX = superWidth/2; 
    CGFloat offsetX = superCenterX - centerX; 
    CGPoint center = self.titleView.center; 

    if (CGRectGetMaxX(self.titleView.frame) + offsetX < self.bounds.size.width && 
     CGRectGetMinX(self.titleView.frame) + offsetX > 0) { 
     center = CGPointMake(self.bounds.size.width/2 + offsetX, self.bounds.size.height/2); 
    } 
    CGSize size = self.titleView.bounds.size; 
    if (size.width > self.bounds.size.width) { 
     size.width = self.bounds.size.width; 
    } 

    self.titleView.frame = CGRectMake(center.x-size.width/2, center.y-size.height/2, size.width, size.height); 
    self.oldFrame = self.titleView.frame; 
} 

die Titelansicht Set:

MDLNavigationTitleContainer *titleView = [[MDLNavigationTitleContainer alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, 44)]; 
self.navigationItem.titleView = titleView;