it-swarm.com.ru

Невозможно установить titleView в центре панели навигации, потому что кнопка назад

Я использую изображение для отображения изображения в моей навигационной панели. Проблема в том, что я не могу правильно установить его из-за кнопки «назад». Я проверил соответствующие вопросы, и раньше у меня была почти та же проблема, которую я решил, но на этот раз я понятия не имею.

Ранее я решил эту проблему с помощью кнопок фальшивой панели, поэтому попытался добавить кнопку фальшивой панели справа (и слева), но это не помогло. 

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

}

Я думаю, что это должно работать нормально, потому что в этом случае titleView имеет кнопки на одной стороне. Есть ли какое-то объяснение, почему это работает с кнопками панели, которые были созданы программно, но не работают с общей кнопкой назад?

47
rihe

UINavigationBar автоматически центрирует его titleView, пока есть достаточно места. Если заголовок не центрирован, это означает, что представление заголовка слишком широкое, чтобы его можно было центрировать, и если вы установите backgroundColor, если ваша UIImageView, вы увидите, что это именно то, что происходит.

Вид заголовка слишком широк, потому что эта панель навигации автоматически изменит размер заголовка, чтобы сохранить его содержимое, используя -sizeThatFits:. Это означает, что ваш вид заголовка всегда будет изменен до размера вашего изображения.

Два возможных исправления:

  1. Изображение, которое вы используете, слишком велико. Используйте правильное изображение размером 44x44 pt с версиями 2x и 3x.

  2. Оберните UIImageView внутри обычного UIView, чтобы избежать изменения размера.

Пример:

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

Пример в Swift 3 версия второго пути Даррена:

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

Я предлагаю вам переопределить функцию - (void) setFrame: (CGRect) fram Вот так: 

- (void)setFrame:(CGRect)frame  { 

    [super setFrame:frame]; //systom function

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

}

так что titleView.center всегда в правильном месте

7
Qun Li

Не используйте titleView.

Просто добавьте ваше изображение в 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

Кун Ли отлично сработал для меня. Вот код 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

Если вы используете настраиваемое представление из пера, обязательно отключите автоматическое расположение файла пера.

3
joslinm

Я создал пользовательскую переменную UINavigationController, после которой единственное, что вам нужно сделать, это вызвать showNavBarTitle(title:font:), когда вы хотите показать, и removeNavBarTitle(), когда вы хотите скрыть:

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

Я считаю, что лучшее место для вызова showNavBarTitle(title:font:) и removeNavBarTitle() - это методы viewWillAppear() и viewWillDisappear() контроллера представления, соответственно:

class YourViewController: UIViewController {

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

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

1) Вы можете попробовать установить свое изображение в качестве фонового изображения UINavigationBar, вызвав 

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

внутри метода viewDidLoad.

Таким образом, он всегда будет по центру, но если у вас есть кнопка back с длинным заголовком в качестве левого элемента навигации, она может появиться в верхней части вашего логотипа. И вам, вероятно, следует сначала создать другое изображение того же размера, что и панель навигации, затем нарисовать ваше изображение в центре, а после этого установить его в качестве фонового изображения.

2) Или вместо того, чтобы установить вид изображения как titleView, вы можете попробовать просто добавить его как подпредставление, чтобы у него не было ограничений, связанных с элементами кнопок правой и левой панели.

1
bzz

В Swift это то, что сработало для меня, но это не лучшее решение (в основном, добавьте его в 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

      }
1

Расширяя ответ Даррена, я решил вернуть sizeThatFits с размером UILabel. Оказывается, это вызывается после layoutSubViews, поэтому метка имеет размер.

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

Также обратите внимание, что у меня есть + titleInset*2, потому что я устанавливаю горизонтальные ограничения следующим образом:

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