Animate UILabel resizing from center?

2019-09-02 04:15发布

问题:

I want to resize my label from center and animate that process. However, the only option I can use there is CGAffineTransformMakeScale with default anchor point of corresponding CALayer.

[UIView animateWithDuration:0.5 animations:^{
    self.title.transform = CGAffineTransformMakeScale(2.0,1.0);
}];

But it squished the text inside. I considered this answer and it looks like the problem is solved in Swift.

However, I can't modify only size part of the frame. How to approach this in Obj C?

回答1:

This will work for you. You just need to give scale for width and height (default 1, which will have no effect). And this will animate your view's frame and set it back to the original.

[UIView animateWithDuration:0.5
                  delay:0
                options:UIViewAnimationOptionBeginFromCurrentState
             animations:(void (^)(void)) ^{
                 self.textLabel.transform=CGAffineTransformMakeScale(3, 1);
             }
             completion:^(BOOL finished){
                 self.textLabel.transform=CGAffineTransformIdentity;
             }];

If you dont want revert effect than you can do like this

[UIView animateWithDuration:0.5
                  delay:0
                options:UIViewAnimationOptionBeginFromCurrentState
             animations:(void (^)(void)) ^{
                 self.textLabel.transform=CGAffineTransformMakeScale(3, 1);
             }
             completion:nil];


回答2:

From what I understood you want to change the size of UILabel not the text via animation. This can be achieved by grabbing a copy of the current label's frame and then modify it and set it back.

i.e

var frame = self.myLabel.frame
// frame modification ...
self.myLabel.frame = frame

Solution

Code

For the sizeTranformAction: you can a simple button and connect it to test the behavior.

class SizeTransformViewController: UIViewController {
    var myLabel: UILabel! = nil

    // MARK: - View lifecycle

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        self.setupLabel()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Setups

    func setupLabel() {
        self.myLabel = UILabel()
        self.myLabel.center = self.view.center
        self.myLabel.text = "Text"
        self.myLabel.sizeToFit()

        self.myLabel.textAlignment = NSTextAlignment.Center
        self.myLabel.backgroundColor = UIColor.redColor()

        self.view.addSubview(self.myLabel)
    }

    // MARK: - Actions

    @IBAction func sizeTranformAction(sender: AnyObject) {
        var frame = self.myLabel.frame
        let size = frame.size
        frame.size = CGSize(width: 2*size.width, height: size.height)
        frame.origin.x = self.view.center.x - size.width

        UIView.animateWithDuration(0.5, delay: 0, options: UIViewAnimationOptions.CurveLinear, animations: { 
            self.myLabel.frame = frame
        }, completion: nil)
    }
}

Output



回答3:

I actually ended up with 2 labels. Animation sequence is following:

  • Create a temporary label with no text in it, attributes like bg color, font, font size, etc should be the same as of your main label.

  • Place the temporary label above your main label. Set main label's text property to nil

  • Animate the frame of main label to a desired value
  • When animation finishes, set back main label's text property to original value (presumably, in completion handler of animateWithDuration:)
  • Hide temporary label / remove it at all


回答4:

You can change your constant to compensate the new width after scaling. Would this help?

layoutIfNeeded()

let scale: CGFloat = 0.72

let consLeft = NSLayoutConstraint(
    item: titleLabel,
    attribute: .left,
    relatedBy: .equal,
    toItem: self,
    attribute: .left,
    multiplier: 1,
    constant: titleLabel.frameWidth * -(1-scale)/2
  )

consLeft.isActive = true

let animations = {
  self.titleLabel.transform = CGAffineTransform(scaleX: scale, y: scale)
  self.layoutIfNeeded()
}
UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseOut],
                     animations: animations,
                     completion: nil)