web-dev-qa-db-fra.com

Impossible de définir titleView au centre de la barre de navigation car le bouton Précédent

J'utilise une vue d'image pour afficher une image dans ma barre de navigation. Le problème est que je ne peux pas le régler correctement au centre à cause du bouton de retour. J'ai vérifié les questions connexes et j'ai eu presque le même problème que je l'avais résolu, mais cette fois, je n'en ai aucune idée.

Auparavant, j'avais résolu ce problème avec de faux boutons de barre, j'ai donc essayé d'ajouter un faux bouton de barre à droite (et à gauche), mais cela n'a pas aidé. 

- (void) searchButtonNavBar {


    CGRect imageSizeDummy = CGRectMake(0, 0, 25,25);

    UIButton *dummy = [[UIButton alloc] initWithFrame:imageSizeDummy];

    UIBarButtonItem
    *searchBarButtonDummy =[[UIBarButtonItem alloc] initWithCustomView:dummy];
    self.navigationItem.rightBarButtonItem = searchBarButtonDummy;

}


- (void)setNavBarLogo {

    [self setNeedsStatusBarAppearanceUpdate];
    CGRect myImageS = CGRectMake(0, 0, 44, 44);
    UIImageView *logo = [[UIImageView alloc] initWithFrame:myImageS];
    [logo setImage:[UIImage imageNamed:@"color.png"]];
    logo.contentMode = UIViewContentModeScaleAspectFit;
    self.navigationItem.titleView = logo;
    [[UIBarButtonItem appearance] setTitlePositionAdjustment:UIOffsetMake(0.0f, 0.0f) forBarMetrics:UIBarMetricsDefault];

}

Je pense que cela devrait fonctionner car dans ce cas, la titleView a des boutons de barres du même côté. Y a-t-il une explication à la raison pour laquelle cela a fonctionné avec les boutons de barre créés par programme mais ne fonctionne pas avec le bouton retour commun?

47
rihe

UINavigationBar centre automatiquement sa titleView tant qu'il y a suffisamment de place. Si le titre n'est pas centré, cela signifie que la vue du titre est trop large pour être centré et si vous définissez backgroundColor si votre UIImageView vous verrez que c'est exactement ce qui se passe.

La vue du titre est trop large car cette barre de navigation redimensionnera automatiquement le titre pour contenir son contenu, à l'aide de -sizeThatFits:. Cela signifie que la vue de votre titre sera toujours redimensionnée à la taille de votre image.

Deux solutions possibles:

  1. L'image que vous utilisez est trop grande. Utilisez une image de 44 x 44 pt de taille appropriée avec les versions 2x et 3x.

  2. Enveloppez UIImageView dans un UIView normal pour éviter le redimensionnement.

Exemple:

UIImageView* imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"test.jpeg"]];
imageView.contentMode = UIViewContentModeScaleAspectFit;

UIView* titleView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 44, 44)];
imageView.frame = titleView.bounds;
[titleView addSubview:imageView];

self.navigationItem.titleView = titleView;
90
Darren

Un exemple dans Swift 3 version du second moyen de Darren:

let imageView = UIImageView(image: UIImage(named: "test"))
    imageView.contentMode = UIViewContentMode.scaleAspectFit
let titleView = UIView(frame: CGRect(x: 0, y: 0, width: 44, height: 44))
    imageView.frame = titleView.bounds
    titleView.addSubview(imageView)

self.navigationItem.titleView = titleView
13
pedrouan

Je vous suggère de remplacer la fonction - (void) setFrame: (CGRect) fram Comme ceci: 

- (void)setFrame:(CGRect)frame  { 

    [super setFrame:frame]; //systom function

    self.center = CGPointMake(self.superview.center.x, self.center.y);   //rewrite function 

}

afin que le titleView.center toujours au bon endroit

7
Qun Li

N'utilisez pas titleView.

Ajoutez simplement votre image à navigationController.navigationBar

CGRect myImageS = CGRectMake(0, 0, 44, 44);
UIImageView *logo = [[UIImageView alloc] initWithFrame:myImageS];
[logo setImage:[UIImage imageNamed:@"color.png"]];
logo.contentMode = UIViewContentModeScaleAspectFit;
logo.center = CGPointMake(self.navigationController.navigationBar.width / 2.0, self.navigationController.navigationBar.height / 2.0);
logo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin;
[self.navigationController.navigationBar addSubview:logo];
6
PowHu

Qun Li a parfaitement fonctionné pour moi. Voici le code Swift 2.3:

override var frame: CGRect {
    set(newValue) {
        super.frame = newValue

        if let superview = self.superview {
            self.center = CGPoint(x: superview.center.x, y: self.center.y)
        }
    }

    get {
        return super.frame
    }
}
5
mikezs

Si vous utilisez une vue personnalisée depuis un nib, veillez à désactiver la mise en page automatique sur le fichier nib.

3
joslinm

J'ai créé une variable UINavigationController personnalisée qui, après être passé, n'a plus qu'à appeler showNavBarTitle(title:font:) lorsque vous souhaitez afficher et removeNavBarTitle() lorsque vous souhaitez masquer:

class NavigationController: UINavigationController {

    private static var mTitleFont = UIFont(name: <your desired font (String)> , size: <your desired font size -- however, font size will automatically adjust so the text fits in the label>)!
    private static var mNavBarLabel: UILabel = {

        let x: CGFloat = 60
        let y: CGFloat = 7
        let label = UILabel(frame: CGRect(x: x, y: y, width: UIScreen.main.bounds.size.width - 2 * x, height: 44 - 2 * y))

        label.adjustsFontSizeToFitWidth = true
        label.minimumScaleFactor = 0.5
        label.font = NavigationController.mTitleFont
        label.numberOfLines = 0
        label.textAlignment = .center

        return label
    }()

    func showNavBarLabel(title: String, font: UIFont = mTitleFont) {
        NavigationController.mNavBarLabel.text = title
        NavigationController.mNavBarLabel.font = font
        navigationBar.addSubview(NavigationController.mNavBarLabel)
    }

    func removeNavBarLabel() {
        NavigationController.mNavBarLabel.removeFromSuperview()
    }
}

Je trouve que le meilleur endroit pour appeler showNavBarTitle(title:font:) et removeNavBarTitle() se trouvent dans les méthodes viewWillAppear() et viewWillDisappear() du contrôleur de vue, respectivement:

class YourViewController: UIViewController {

    func viewWillAppear() {
        (navigationController as! NavigationController).showNavBarLabel(title: "Your Title")
    }

    func viewWillDisappear() {
        (navigationController as! NavigationController).removeNavBarLabel()
    }
}
2
shoe

1) Vous pouvez essayer de définir votre image comme image d’arrière-plan de UINavigationBar en appelant 

[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"color.png"] forBarMetrics:UIBarMetricsDefault];

dans la méthode viewDidLoad.

De cette façon, il sera toujours centré, mais si vous avez le bouton back avec un titre long comme élément de navigation de gauche, il peut apparaître au-dessus de votre logo. Et vous devriez probablement au début créer une autre image avec la même taille que la barre de navigation, puis dessinez votre image en son centre, puis définissez-la comme image d'arrière-plan.

2) Ou au lieu de définir votre vue d'image sur titleView, vous pouvez simplement ajouter l'ajout en tant que sous-vue afin d'éviter les contraintes liées aux éléments des boutons des barres de droite et de gauche.

1
bzz

Dans Swift, c’est ce qui a fonctionné pour moi, mais ce n’est pas la meilleure solution (en gros, ajoutez-la à navigationBar):

    let titleIV = UIImageView(image: UIImage(named:"some"))
        titleIV.contentMode = .scaleAspectFit
        titleIV.translatesAutoresizingMaskIntoConstraints = false

      if let navigationController = self.navigationController{
            navigationController.navigationBar.addSubview(titleIV)
            titleIV.centerXAnchor.constraint(equalTo:  
navigationController.navigationBar.centerXAnchor).isActive = true
            titleIV.centerYAnchor.constraint(equalTo: navigationController.navigationBar.centerYAnchor).isActive = true
      }
      else{
            view.addSubview(titleIV)
            titleIV.topAnchor.constraint(equalTo: view.topAnchor, constant: UIApplication.shared.statusBarFrame.height).isActive = true
            titleIV.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

      }

Pour prolonger la réponse de Darren, un correctif pour moi était de retourner une sizeThatFits avec la taille UILabel. Il s'avère que cela s'appelle après layoutSubViews afin que l'étiquette ait une taille.

override func sizeThatFits(_ size: CGSize) -> CGSize {
    return CGSize(width: titleLabel.frame.width + titleInset*2, height: titleLabel.frame.height)
}

Notez aussi que j'ai + titleInset*2 parce que je règle les contraintes horizontales comme ceci:

titleLabel.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: titleInset),
titleLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -titleInset)
0
richy