2010-09-10 9 views
27

Zauważyłem, że pozycja titleView zależy od tytułu prawego klawisza pola. Jak mogę zamiast tego ustawić ramkę titleView na środek?Dostosowywanie ramki navigationItem.titleView?

Próbowałem już ustawić titleView.frame, ale na próżno.

Oto kod:

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

ktoś? ktoś pomoże! –

+0

Mam ten sam problem! Przyciski po lewej lub po prawej stronie powodują, że tytułView jest aktualny, nawet po ustawieniu go dokładnie w layoutSubviews – quantumpotato

Odpowiedz

46

Czasami pomiędzy widokiem kontrolera widoku. ViewAppear: & viewDidAppear :, pasek nawigacyjny zmienia położenie titleView i zmienia rozmiar, aby pasował w razie potrzeby. Może się to okazać niewykonane, ponieważ pasek nawigacji nie chce zmieniać rozmiaru tytułu, aby zmieścić się między przyciskami. Wygląda na to, że próbujesz wyśrodkować widok tytułowy, jeśli jest wystarczająco mały, ale jeśli nie, przeniesiesz titleView poza centrum, a wtedy myślę, że tylko w ostateczności zmieni się rozmiar. Efekt jest taki, że titleView zajmuje całą przestrzeń między tymi dwoma przyciskami, jeśli jej textAlignment jest wyśrodkowany, wtedy zostanie wyśrodkowany w przestrzeni , ale nie w środku względem całego ekranu. Możesz to zobaczyć na ekranie.

Jedna z odpowiedzi polega na zmniejszeniu tytułu titleView, aby pasek nawigacyjny mógł go wyśrodkować, więc po ustawieniu titleView.frame spróbuj użyć wartości 160 zamiast 180. To jest do bani, że tworząc widok tak programowo jak ty, trzeba umieścić oszacowanie dla tej szerokości w kodzie. To, co byłoby dobre, to sposób na zmaksymalizowanie tej przestrzeni, pozostając skoncentrowanym.

Można rozpocząć od tytułu titleView będącego szerokością ekranu, a następnie po zmianie paska tytułu titleView.frame, zaktualizuj go ponownie w widoku kontrolera widokuDidAppear :. Korzystając z dopasowanego titleView.frame.origin.x i size.width wraz z szerokością ekranu, możesz obliczyć największy z lewego marginesu prawego &, a następnie ustawić origin.x na to, size.width na szerokość ekranu minus razy 2. To jednak nie działa, dopóki animacja nie wyświetli obrazu, a potem jest widoczna. Możesz ukryć titleView w viewWillAppear: następnie odkryć w viewDidAppear: po wyśrodkowaniu, więc zamiast przesuwać się z niecentralnym tytułem, który jest następnie przesuwany, wsuwa się bez tytułu, który następnie pojawia się.

Lepszą możliwością jest stworzenie tytułu Wyświetl własną podklasę UIView (lub UILabel lub cokolwiek innego) i przeskaluj setFrame, aby zmienić rozmiar, aby pozostać wyśrodkowany w swoim superzaminie. Jeśli kiedykolwiek skończę to robić, opublikuję to tutaj. A może ktoś inny zna inne miejsce, w którym można zmienić ramkę titleView po jej aktualizacji, ale zanim widok pojawi się bez podklasy widoku.

+2

To powinno być naprawdę oznaczone jako odpowiedź. Używając tego, ustawiłem szerokość widoku dokładnie tak, jak powinno być, aby dopasować tekst do mojej etykiety. To działało świetnie! – GendoIkari

+0

Dzięki za napisanie tej odpowiedzi pomogło mi to bardzo. –

+0

Zrobiłem obserwację właściwości ramki navigationBar i zrobiłem to, co zasugerowałeś, zmieniając ramkę nawigacji. W moim przypadku problem dotyczył zmian orientacji. –

0

sam problem tutaj. Wdrażanie etykiety autoscrolling jako titleView. Aby długi tekst w tytule nawigacji mógł być przewijany automatycznie, aby użytkownik mógł zobaczyć wszystko. Wszystkie problemy z nieznanymi rzeczywistymi wymiarami titleView zapobiega centrowaniu tekstu w najprostszym przypadku specjalnym: gdy tekst etykiety pasuje i nie jest wymagane automatyczne przewijanie (jak ustawienie tekstu na tytuł własności elementu 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

Proszę nie wywoływać wydania na obiekcie Autorelease ... – Lolloz89

17

Po skonfigurowaniu titleView lub titleLabel, zadzwoń sizeToFit na nim również upewnić titleLabel.textAlignment = UITextAlignmentCenter. Zostanie wyśrodkowany na szerokość paska nawigacyjnego, a nie w przestrzeni między krawędzią przycisku a dalszą krawędzią paska nawigacyjnego.

+1

to po prostu działa. kiedy po raz pierwszy przeczytałem odpowiedź, przeczytałem długą "niemożliwą" odpowiedź i trochę przestraszyłem się. to powinno być oznaczone jako właściwe. – shem

+0

To działa całkiem dobrze. Działa również na innych UIViews, takich jak UIButton. –

12

Żadna z sugestii tutaj naprawdę nie zadziałała.Mój problem polegał na tym, że ustawiałem titleView, gdy pasek nawigacyjny znajdował się pośrodku jego przejścia - dostałbym ten dziwny jitter, w którym tytuł wyświetliłby się w lewo, a następnie wylądował z powrotem na środku.

skończyło się następujący pomysł i nadrzędnym setFrame smallduck, był tak proste, jak:

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

działa natychmiast! –

1

Moje rozwiązanie było ręcznie zmienić rozmiar paska nawigacji w viewDidAppear:

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

... potem możesz także zmienić położenie widoku tytułowego. Zauważyłem, że głównym problemem było to, że pasek nawigacji również się zmienił, więc przywróciłem go do normalnego rozmiaru. Mam regularny rozmiar od debugowania i sprawdzania jego rozmiaru w viewDidLoad zanim został zmodyfikowany ...

+0

Niewłaściwa opcja opcji –

+0

To było najbliższe rozwiązanie, które sprawdziło się u mnie. Musiałem wykonać instrukcję przełączania na podstawie obrazu przycisku, który może się różnić w zależności od tego, co wybrał użytkownik. Zebrałem informacje z debuggera o rozmiarze i odpowiednio dostosowałem. – invertedfjord

6

Możesz spróbować ustawić ramkę początkowo na CGRectZero i wywołać sizeToFit. Poniżej znajduje się kod, którego użyłem, aby zmienić tekst tytułu i upewnić się, że nadal jest wyśrodkowany. Miałem przycisk z tyłu po lewej.

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

zamiast ustawiać ramkę na CGRectZero możesz po prostu zrobić 'UILabel * label = [[przypisywanie UILabel]]; –

0

Mam nieco inny przypadek użycia (przesunięcie pionowe UIButton jako titleView na iOS 7). Po długim czasie wymyśliłem użycie właściwości UIButton, aby przesunąć zawartość w jego ramce.

0

Jedynym sposobem, jaki udało mi się rozwiązać ten problem, to nie używać UINavigationItems. Insted wykorzystywać dwa różne poglądy na stronie przycisk EiA z UINavigationBar tak:

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

} 

i setButtons na nim tak:

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

Wtedy tytuł będzie nie ruszaj się! ponieważ widoki UIButtons są tej samej szerokości.

-1

Wystarczy dodać niewidzialny przycisk (bez tekstu) po prawej stronie paska nawigacyjnego, i zmienić ją rozmiar, aby na przykład 20 px

0

byłem wykonawczych tytuł dwa wiersz podobny do czegoś WhatsApp robi (tytuł i podtytuł) .

Naprawiłem ten problem, podklasy UINavigationController i przesłonięcie viewDidLayoutSubviews().

Moja titleView wygląda następująco (w 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 

My 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() 

Uwaga: Sztuką jest mieć widok otoki wokół titleView który można określić za pomocą paska nawigacji. Następnie dostosuj ramkę swojego tytułu Zobacz, czego pragniesz.

0

Ostatnio mam ten sam problem, mam złożony widok tytułu, którego zawartość może się zmieniać, więc chcę pokazać jak najwięcej treści, mój lewy przycisk i prawy przycisk mają inną szerokość, więc jeśli Ustawiam ją na długą szerokość, pasek nawigacji nie wyśrodkowuje. Jak możesz wiedzieć, kiedy lewy lub prawy przycisk paska jest bardzo długi, nie można wyśrodkować widoku tytułu, więc chcę go wyśrodkować tak bardzo, jak to możliwe.

Gdy ustawimy widok na self.navigationItem.titleView, pasek nawigacyjny będzie zarządzał ramką widoku tytułu, ciężko jest ją wyśrodkować bezpośrednio, więc podklasuję widok, który działa jak widok kontenera widoku rzeczywistego widoku tytułu, ustawiam jego szerokość za pomocą ekranu szerokość, UINavigationBar z ustawieniem jego ramki na wartość właściwości z uwzględnieniem jej przycisku przycisku w lewo/w prawo.

Widok pojemnik jest MDLNavigationTitleContainer i prawdziwy tytuł widok jest MDLMessagesNavigationTitleView, MDLMessagesNavigationTitleView jest zarządzany przez układ automatycznej, jak to super widok jest MDLNavigationTitleContainer, za każdym razem jego szerokość zmienia, layoutSubviews zostanie wywołana. Kod w layoutSubviews wydaje się nieco dziwny, służy do obsługi animacji push/pop.

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

ustawić widok tytuł:

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