1

When going to a secondary page, I'm trying to slide the back button in from the left over a period of 0.33 seconds. Right now the animation doesn't appear to be doing that, even after slowing duration down to 2 seconds for visual clarification. Was wondering if anyone could tell me what I've done wrong in my code and how to correct it?

Going to come out and say that I likely am just misunderstanding how some aspect of animation works.

func addBackButton() {
        let backButton = UIButton(type: .custom)
        backButton.setImage(#imageLiteral(resourceName: "backArrow"), for: .normal)
        backButton.setTitle("", for: .normal)
        backButton.setTitleColor(backButton.tintColor, for: .normal)
        backButton.addTarget(self, action: #selector(backAction), for: .touchUpInside)
        let backBarButtonItem = UIBarButtonItem(customView: backButton)
        backBarButtonItem.customView?.transform = CGAffineTransform(translationX: -backButton.frame.width, y: 0)
        navigationItem.leftBarButtonItems?.insert(backBarButtonItem, at: 0)
        UIView.animate(withDuration: 2, delay: 0.5, animations: {
            backBarButtonItem.customView?.transform = CGAffineTransform(translationX: 2 * backButton.frame.width, y: 0)
        })
    }

2 Answers 2

1

You just need to put this custom button inside a containerView and set that containerView as the UIBarButtonItem's custom view. Your setup will look like this,

let containerFrame = CGRect(origin: .zero, size: CGSize(width: 44.0, height: 44.0))
let container = UIView(frame: containerFrame)

let buttonFrame = CGRect(origin: CGPoint(x: -100, y: 0), size: CGSize(width: 44, height: 44))  
let backButton = UIButton(frame: buttonFrame)
backButton.setImage(#imageLiteral(resourceName: "backArrow"), for: .normal)
backButton.setTitle("", for: .normal)
backButton.setTitleColor(backButton.tintColor, for: .normal)
backButton.addTarget(self, action: #selector(backAction), for: .touchUpInside)
container.addSubview(backButton)

let backBarButtonItem = UIBarButtonItem(customView: container)
UIView.animate(withDuration: 2, delay: 0.5, animations: {
    backButton.transform = CGAffineTransform(translationX: 2 * backButton.frame.width, y: 0)
})

You can check why you need to wrap your custom button inside another UIView here.

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

1 Comment

This answer solved it, though I upvoted @Procrastin8 as well for the helpfulness of the transform identity. Thank both of you
1

UIBarButtonItem is not a UIView subclass for a reason. If this is the effect you want (platform consistency says you should use UINavigationItem.setLeftBarButtonItems(_:animated:)) then you should instead add the backButton to your view hierarchy, animate it in, then set it as the leftBarButtonItem in the completion block.

Keep in mind you will have to likely add it to the navigation bar view hierarchy so it appears on top of it. This approach also means you are basically duplicating layout code of the navigation bar and you'll have to figure out where it's supposed to end up.

navigationController?.navigationBar.addSubview(backButton)

// layout back button in it's final spot here, either via constraints or frame math

backButton.transform = CGAffineTransform(translationX: -(button.bounds.width + leadingSpacing), translationY: 0.0)

UIView.animate(duration: 0.3, animations: {
    backButton.transform = .identity
} { completed in
    self.navigationItem.leftBarButtonItem = UIBarButtonItem
}

Comments

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.