0

I am setting navigation bar back button in AddDelegate but it is not setting properly.

I have tried below code :

let backButtonImage = backImage?.withRenderingMode(.alwaysOriginal).resizableImage(withCapInsets: UIEdgeInsetsMake((backImage?.size.height)!, (backImage?.size.width)!, 0, 0))
UIBarButtonItem.appearance().setBackButtonBackgroundImage(backButtonImage, for: .normal, barMetrics: .default)
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(-400, 0), for: .default)

from here .

But the UI is not correct:

enter image description here

I have also tried below code :

UINavigationBar.appearance().backIndicatorImage = backButtonImage
UINavigationBar.appearance().backIndicatorTransitionMaskImage = backButtonImage
UIBarButtonItem.appearance().setBackButtonTitlePositionAdjustment(UIOffsetMake(0, -80.0), for: .default)

which looks like this:

enter image description here

But it is giving constraint issues in the terminal:

[LayoutConstraints] Unable to simultaneously satisfy constraints.
    Probably at least one of the constraints in the following list is one you don't want. 
    Try this: 
        (1) look at each constraint and try to figure out which you don't expect; 
        (2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x600000098510 UILayoutGuide:0x6040007aca20'BackButtonGuide(0x7f8143611390)'.height == 44   (active)>",
    "<NSLayoutConstraint:0x60000029e320 _UIButtonBarButton:0x7f814349d110.top == UILayoutGuide:0x6040007aca20'BackButtonGuide(0x7f8143611390)'.top   (active)>",
    "<NSLayoutConstraint:0x60000029de20 _UIButtonBarButton:0x7f814349d110.bottom == UILayoutGuide:0x6040007aca20'BackButtonGuide(0x7f8143611390)'.bottom   (active)>",
    "<NSLayoutConstraint:0x60400049d790 _UIModernBarButton:0x7f81434a4800'Back'.lastBaseline == UILayoutGuide:0x6000001b51c0'UIViewLayoutMarginsGuide'.bottom - 80   (active)>",
    "<NSLayoutConstraint:0x60400049d1a0 _UIModernBarButton:0x7f81434a4800'Back'.top >= _UIButtonBarButton:0x7f814349d110.top   (active)>",
    "<NSLayoutConstraint:0x600000481040 UIButtonLabel:0x7f81434a30d0'Back'.centerY == _UIModernBarButton:0x7f81434a4800'Back'.centerY + 1.5   (active)>",
    "<NSLayoutConstraint:0x60000029ea00 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x6000001b51c0'UIViewLayoutMarginsGuide']-(16)-|   (active, names: '|':_UIButtonBarButton:0x7f814349d110 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x600000481040 UIButtonLabel:0x7f81434a30d0'Back'.centerY == _UIModernBarButton:0x7f81434a4800'Back'.centerY + 1.5   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.


[LayoutConstraints] Unable to simultaneously satisfy constraints.
Probably at least one of the constraints in the following list is one you don't want.
    Try this:
    (1) look at each constraint and try to figure out which you don't expect; 

(2) find the code that added the unwanted constraint or constraints and fix it. 
(
    "<NSLayoutConstraint:0x60000029f1d0 _UIModernBarButton:0x7f814360f630.bottom == UILayoutGuide:0x6040007ac940'UIViewLayoutMarginsGuide'.bottom + 84.5   (active)>",
    "<NSLayoutConstraint:0x600000287bc0 V:[_UIModernBarButton:0x7f814360f630]-(>=0)-|   (active, names: '|':_UIButtonBarButton:0x7f814360d8a0 )>",
    "<NSLayoutConstraint:0x604000488930 'UIView-bottomMargin-guide-constraint' V:[UILayoutGuide:0x6040007ac940'UIViewLayoutMarginsGuide']-(16)-|   (active, names: '|':_UIButtonBarButton:0x7f814360d8a0 )>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x60000029f1d0 _UIModernBarButton:0x7f814360f630.bottom == UILayoutGuide:0x6040007ac940'UIViewLayoutMarginsGuide'.bottom + 84.5   (active)>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.

Is there any other way of doing it or I am doing something wrong ?

2 Answers 2

2

From reference of @Rajamohan-s answer:

Change UINavigationBar back button text and font from AppDelegate using Swift

You can do it with below code;

 extension UINavigationItem{

    override open func awakeFromNib() {
        super.awakeFromNib()

        let backItem = UIBarButtonItem()
        backItem.title = "Hello"


        if let font = UIFont(name: "Copperplate-Light", size: 32){
            backItem.setTitleTextAttributes([NSFontAttributeName:font], for: .normal)
        }else{

            print("Font Not available")
        }
        /*Changing color*/
        backItem.setTitleTextAttributes([NSForegroundColorAttributeName: UIColor.green], for: .normal)

        self.backBarButtonItem = backItem
    }

}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for your answer..... but this code is not working in swift 4.I want an image in back button and no title.
I don't know If there is any code depreciated in Swift 4. Did you try converting it to Swift 4 in Xcode?
0

Someone might post a better answer but my solution was giving up on these nonsense with navigation bar and its appearance so what I did was create a base view controller for all view controllers I use inside the application. (I do that anyway so I am able to control things like status bar style, translation...).

So my base view controller looks somewhat like:

class BaseViewController: UIViewController {

    @IBInspectable var backButtonImage: UIImage? = /*Use your default here*/

    override func viewDidLoad() {
        super.viewDidLoad()

        if let backButtonImage = backButtonImage {
           navigationItem.leftBarButtonItem = UIBarButtonItem(image: backButtonImage, style: .plain, target: self, action: #selector(onBack))
           navigationController?.interactivePopGestureRecognizer?.delegate = self
        }
    }

    @objc private func onBack() {
        navigationController?.popViewController(animated: true)
    }
}

extension BaseViewController: UIGestureRecognizerDelegate {

    func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        return (navigationController?.viewControllers.count ?? 0) > 1
    }

}

So the back button is completely overridden for all view controllers to show desired image. This then produces an issue that the swipe breaks to go back to previous view controller so the delegate is taken to fix it.

Am I not very pleased with my solution but it seems to be the only one that woks consistently throughout the iOS versions.

Do note that if you use the stupid controllers like UITableViewController or UITabBarViewController you will need to subclass those as well and add the same code in them.

As for the navigation view controller I suggest you subclass it as well and/or even subclass the UINavigationBar. This way you will have a complete control over what is going on and the appearance of it.

3 Comments

I haven't tried your code yet. I have on question..... In above question I have mentioned the second scenario...... in which I am getting constraint warning..... can I ignore those constraint issues as in that scenario I am getting the exact UI which I want.
@Amit Most likely you may ignore it. At least if it works on most iOS versions you are targeting. But make sure you test it on all future versions. On the other hand the screenshot you provided looks a but like your button is not centered vertically, it should be moved upwards a few pixels (or is it just me?).
Yes it is not centred. For that I have used UINavigationBar.appearance().setTitleVerticalPositionAdjustment(5.0, for: .default) .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.