Search code examples
iosswiftuibarbuttonitem

Animate (Rotate) UIBarButtonItem custom buttons


All I want to do is rotating the UIBarButtonItem when it is clicked.

I followed this post Rotate UIBarButtonItem Swift, but it is not working.

The difference is:

enter image description here

1- I set the image on runtime when view is loaded:

     showHideBtn.image = showHeaderimage

2- I have two buttons in my right Bar button items:

Here is my code:

 @IBAction func rotateAction(_ sender: Any) {
    if(!self.isVertical)
    {
        UIView.animate(withDuration: 0.2, animations: { 

  self.navigationItem.rightBarButtonItem?.customView?.transform =  CGAffineTransform(rotationAngle: 90 * .pi / 180)
        }, completion: { (finished) in
            self.isVertical = true
        })
    }else{
        UIView.animate(withDuration: 0.2, animations: {
            self.navigationItem.rightBarButtonItem?.customView?.transform =  CGAffineTransform.identity
        }, completion: { (finished) in
            self.isVertical = false
        })
    }

}

What am I doing wrong?

Updated code:

   DispatchQueue.main.async {
     if(!self.isVertical) {

        UIView.animate(withDuration: 0.2, animations: {

            self.navigationItem.rightBarButtonItem?.customView?.transform =  CGAffineTransform(rotationAngle: 90 * .pi / 180)
        }, completion: { (finished) in
           self.isVertical = true
        })


    }else {
        UIView.animate(withDuration: 0.2, animations: {

            self.navigationItem.rightBarButtonItem?.customView?.transform =  CGAffineTransform(rotationAngle: 90 * .pi / 180)
        }, completion: { (finished) in
           self.isVertical = false
        })

    } }

Show button property:

enter image description here


Solution

  • It could be how you've set the custom view in the bar item. Maybe this self.navigationItem.rightBarButtonItem?.customView?. is returning nil. Anyway, here is a working version:

    Creating the custom UIBarButtonItem:

    let button1: UIButton = UIButton(frame: CGRect(x: 0, y: 0, width: 60, height: 30))
    
    let button2: UIButton = UIButton(frame: CGRect(x: 70, y: 0, width: 60, height: 30))
    
    override func viewDidLoad(_ animated: Bool) {
        super.viewDidLoad(animated)
        button1.backgroundColor = .gray
        button1.setTitle("CustomButton", for: .normal)
        button1.addTarget(self, action: #selector(rotateAction(_:)), for: .touchUpInside)
        let barItem1: UIBarButtonItem = UIBarButtonItem(customView: button1)
    
        button2.backgroundColor = .gray
        button2.setTitle("CustomButton", for: .normal)
        button2.addTarget(self, action: #selector(rotateAction(_:)), for: .touchUpInside)
        let barItem2: UIBarButtonItem = UIBarButtonItem(customView: button1)
    
        navigationItem.setRightBarButtonItems([barItem1, barItem2], animated: true)
    }
    

    Animate the tapped button:

    @objc func rotateAction(_ sender: UIButton) {
        let customView = sender
    
        let transform: CGAffineTransform = isVertical ? .identity : CGAffineTransform(rotationAngle: 90 * .pi / 180)
    
        UIView.animate(withDuration: 0.2, animations: {
            customView.transform =  transform
        }, completion: { (finished) in
            self.isVertical = !self.isVertical
        })
    }
    

    To avoid replacing the bar button item/items set from storyboard, get those button items and create an array of bar button item including those with the ones you created in code:

    let existingBarItems: [UIBarButtonItem] = navigationItem.rightBarButtonItems ?? []
    let rightBarItems = existingBarItems = [yourCustomButtonItem]
    navigationItem.setRightBarButtonItems(rightBarItems, animated: true)
    

    And make sure your custom bar button item's frame doesn't intersect with existing buttons.