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?
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];
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
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
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)