Animating only the image in UIBarButtonItem

后端 未结 4 643
暖寄归人
暖寄归人 2021-01-03 07:11

Ive seen this effect in 2 apps and I REALLY want to find how to do it.

The animation is in a UIBarButtonItem, and is only to the image. The image is a + symbol, and

相关标签:
4条回答
  • 2021-01-03 07:21

    So the answer for this is you have to make a instance of the Image view, then set it up with no resizing and view mode is centered. Then add the image view to a UIButton with custom type, and then use the button as the custom view for the bar item.

    - (IBAction)animate {
        [UIView animateWithDuration:0.5 delay:0.0 options:UIViewAnimationOptionCurveLinear animations:^{
            imageView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(45));
        } completion:^(BOOL finished) {
            imageView.transform = CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0));
            if ([imageView.image isEqual:[UIImage imageNamed:@"Add.png"]]) {
                imageView.image = [UIImage imageNamed:@"Close.png"];
            }
            else imageView.image = [UIImage imageNamed:@"Add.png"];
        }];
    }
    
    - (void)viewDidLoad
    {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Add.png"]];
        imageView.autoresizingMask = UIViewAutoresizingNone;
        imageView.contentMode = UIViewContentModeCenter;
        UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
        button.frame = CGRectMake(0, 0, 40, 40);
        [button addSubview:imageView];
        [button addTarget:self action:@selector(animate) forControlEvents:UIControlEventTouchUpInside];
        imageView.center = button.center;
        barItem = [[UIBarButtonItem alloc] initWithCustomView:button];
        navItem.rightBarButtonItem = barItem;
    }
    
    0 讨论(0)
  • 2021-01-03 07:22

    You don't have to use a button as a custom view, it works in fact with less code using a UIImageView and adding a UITapGestureRecognizer.

    I hope my solution below helps someone b/c I struggled with this for a long time until I got the bar button item to receive taps and get it to work with all the features I wanted. In my case, I made an "alert bell" bar button item that jingles when there are notifications, and then segues to a new tableview controller when tapped.

    This was my solution (Swift 5):

    @IBOutlet weak var notifyBell: UIBarButtonItem!
    
        func updateNumNotesAndAnimateBell(_ numNotes: Int) {
    
        guard let image = UIImage(named: "alertBellFill_\(numNotes)") else { return }
        let imageView = UIImageView(image: image)
        notifyBell.customView = imageView
        notifyBell.customView?.contentMode = .center
        let tap = UITapGestureRecognizer(target: self, action: #selector(notifyBellPressed))
        notifyBell.customView?.addGestureRecognizer(tap)
    
        let scaleTransformA = CGAffineTransform(scaleX: 0.8, y: 0.8)
        let rotateTransformA = CGAffineTransform(rotationAngle: 0.0)
        let hybridTransformA = scaleTransformA.concatenating(rotateTransformA)
        let rotateTransformB = CGAffineTransform(rotationAngle: -1*CGFloat.pi*20.0/180.0)
        let hybridTransformB = scaleTransformA.concatenating(rotateTransformB)
    
        notifyBell.customView?.transform = hybridTransformA
        UIView.animate(withDuration: 3,
                       delay: 1,
            usingSpringWithDamping: 0.1,
            initialSpringVelocity: 10,
            options: [.allowUserInteraction, .curveEaseInOut],
            animations: {
                self.notifyBell.customView?.transform = numNotes > 0 ? hybridTransformB : scaleTransformA
            },
            completion: nil
        )
    
    }
    @objc func notifyBellPressed(_ sender: UIBarButtonItem) {
        performSegue(withIdentifier: "goToNotificationsTVC", sender: self)
    }
    

    Key discoveries for me were that:

    -- .allowUserInteraction must be included in the animate options, otherwise the UIBarButtonItem won't be active until the animation completes.

    -- You will likely have to declare YourBarButtonItem.customView?.contentMode = .center when using CGAffineTransform(rotationAngle: ) or else it will distort your image when it tries to rotate.

    -- The code above includes a scale animation and rotate animation that is different depending on how many notifications I have. With zero notifications, the image is an empty bell, else, it displays the number of notifications in the bell image. I probably could've done this with an updating label, but I had already gone the route of making separate PNGs for each so this worked nicely.

    0 讨论(0)
  • 2021-01-03 07:29

    Recently had to do the same thing in Swift. I created a tutorial that includes starter and final projects, and goes step-by-step with some tips sprinkled in. The code looks like this:

    @IBOutlet weak var rightBarButton: UIBarButtonItem! {
        didSet {
            let icon = UIImage(named: "star")
            let iconSize = CGRect(origin: CGPointZero, size: icon!.size)
            let iconButton = UIButton(frame: iconSize)
            iconButton.setBackgroundImage(icon, forState: .Normal)
            rightBarButton.customView = iconButton
            rightBarButton.customView!.transform = CGAffineTransformMakeScale(0, 0)
    
            UIView.animateWithDuration(1.0,
                delay: 0.5,
                usingSpringWithDamping: 0.5,
                initialSpringVelocity: 10,
                options: .CurveLinear,
                animations: {
                    self.rightBarButton.customView!.transform = CGAffineTransformIdentity
                },
                completion: nil
            )    
    
            iconButton.addTarget(self, action: "tappedRightButton", forControlEvents: .TouchUpInside)        
        }
    }
    
    func tappedRightButton(){
        rightBarButton.customView!.transform = CGAffineTransformMakeRotation(CGFloat(M_PI * 6/5))
        UIView.animateWithDuration(1.0) {
            self.rightBarButton.customView!.transform = CGAffineTransformIdentity
        }
    }
    
    0 讨论(0)
  • 2021-01-03 07:29

    I wanted to keep the expanded tapping size that the native UIBarButtonItem view provides (such as -initWithBarButtonSystemItem:target:action: versus -initWithCustomView:).

    Here's a basic implementation of my code.

    - (void)setup {
        self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(navigationBarRightAction)];
    }
    
    - (void)navigationBarRightAction {
        UIView *itemView = [self.navigationItem.rightBarButtonItem performSelector:@selector(view)];
        UIImageView *imageView = [itemView.subviews firstObject];
    
        if (self.shouldRotate) {
            imageView.contentMode = UIViewContentModeCenter;
            imageView.autoresizingMask = UIViewAutoresizingNone;
            imageView.clipsToBounds = NO;
            imageView.transform = CGAffineTransformMakeRotation(M_PI_4);
    
        } else {
            imageView.transform = CGAffineTransformIdentity;
        }
    }
    
    0 讨论(0)
提交回复
热议问题