Joey Nash
Joey Nash

Reputation: 45

Slide UIBarButtonItem from the left

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

Upvotes: 1

Views: 187

Answers (2)

Procrastin8
Procrastin8

Reputation: 4503

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
}

Upvotes: 1

Kamran
Kamran

Reputation: 15248

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.

Upvotes: 1

Related Questions