4
votes

I have a UIView as container with a UILabel inside like this:

-------------       ---------
|           |       |       |
|Label text |       |Label..|
|           |  -->  |       |
|           |       |       |
|           |       |       |
-------------       ---------

Now when I use:

UIView animateWithDuration:animations:

and try to set the width smaller of the UIView (which contains the UILabel) then during the animation the UILabel suddenly replace with "..." without having smooth transition to it. I setup the UILabel autoresizingmask to UIViewAutoresizingFlexibleWidth, UIViewAutoresizingFlexibleRightMargin to keep it left and set the contentmode to left.

Trying other content mode like:Scale to fill, Aspect fit, Aspect fill doesnt solve my problem either, as they scale the text and then it looks strange.

Anybody have an idea how to get smooth transition for the UILabel?

4

4 Answers

5
votes

I animated my label the described way some time ago, but you have to put some afford in it. Basic idea: - Add the label to a containerview with clipsToBounds:YES. - Do Not animate the label frame, instead animate the frame of the containerview, so your label will have a smooth transition. - Use a seperate Label for the Elipsis (...) so you can animate this part too.

0
votes

Unfortunately labels don't scale; changing the frame of it changes where the text is placed, but the size of the text does not scale this way. So basic animation is out, an alternative is to fire off a timer that shrinks the frame of the label by a predetermined amount each time the timer fires.

Of course you'll want to set the labels setAdjustsFontSizeToFitWidth property to YES.

NOTE: If possible avoid actually firing a timer every 5/1000's of a second.

- (void)fireTimer
{
    timer = [NSTimer scheduledTimerWithTimeInterval:0.005 target:self selector:@selector(animate) userInfo:nil repeats:YES];
}

- (void)animate
{
    [label setAdjustsFontSizeToFitWidth:YES];
    if (label.frame.size.width > 100) {
        [label setFrame:CGRectMake(label.frame.origin.x, label.frame.origin.y, label.frame.size.width-1, label.frame.size.height)];
    }else{
        [timer invalidate];
        timer = nil;
    }
}
0
votes

I was having a similar problem when resizing a UILabel during autorotation and solved it by using the CADisplayLink like this.

First, call the displayLinkTimer in the willAnimateRotationToInterfaceOrientation method.

displayLinkTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(resizeTextLabel)];
[displayLinkTimer addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

Then, resize the label by resizing it at the same rate an invisible UIView that I created called textView. The textView has a frame identical to what I want my UILabel's frame to be and its size is being changed in the willAnimateRotationToInterfaceOrientation method. I was able to resize at the same rate by accessing the textView's presentationLayer.

- (void)resizeTextLabel{
 if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) {
    if (textLabel.frame.size.width < textView.frame.size.width -20) {
        textLabel.frame = CGRectMake(0, 0, [[textView.layer presentationLayer] frame].size.width, [[textView.layer presentationLayer] frame].size.height);
    }else{
        [timer invalidate];
        timer = nil;
    }
 }
 else{
    if (textLabel.frame.size.width > textView.frame.size.width -20) {
        textLabel.frame = CGRectMake(0, 0, [[textView.layer presentationLayer] frame].size.width, [[textView.layer presentationLayer] frame].size.height);
    }else{
        [timer invalidate];
        timer = nil;
    }
  }
}

Hope this helps someone.

0
votes

Old question, but this helped me:

    override var frame: CGRect {
        didSet {
            self.layoutSubviews()
        }
    }