简体   繁体   中英

Animate UILabel text change inside UITableViewCell

I want to animate a UILabel inside a custom UITableViewCell when the text property changes.

I have the animation working fine, except the animation is firing every time the cell comes into view while scrolling and also when calling [myTableView reloadData] .

Using something as simple as

if (![myLabel.text isEqualToString:newText]) {
    // change myLabel.text with animation here. 
}

Does not work.

I understand why this is happening. If I create a new cell each time, I could check if myLabel.text has a string, if so, is it different, and then apply the changes. However there are sometimes way too many cells to display.

When reusing cells, myLabel.text will almost always already have a string, and will almost always be different to what I want to set it to. So the above checks won't work. They will cause the animations to fire anyway.

The only way I can think of getting this to work is to create an array with the last known values in myLabel.text and do a comparison, but this list would be huge!

I have no idea where to begin solving this issue.

All I want is for myLabel to do a little flip/backgroundColor animation inside my subclassed UITableViewCell when the text property changes. The closest solutions I have found will cause all labels in the tableviewcell to run the animation.

I also can't check myLabel.text before giving it a string because it's always getting reused.

I'm starting to get the impression that this just can't be done.

If you've subclassed UITableViewCell , you can override the default prepareForReuse method. In this method, set your label's text property to nil .

- (void)prepareForReuse {
    [super prepareForReuse];
    myLabel.text = nil;
}

Now:

if (myLabel.text && ![myLabel.text isEqualToString:newText]) {
    // change myLabel.text with animation here. 
}

Now the text should only animate if it's been changed from one text to a new text.

prepareForReuse is called on the cell by the tableview's dequeueReusableCell method.

#pragma mark - Timer Function
-(void)callAfteroneSecond_deals
{
    NSArray *indexes = [self.tbl_deals indexPathsForVisibleRows];
    MYTableViewCell *cell = (MYTableViewCell *)[_tbl_deals cellForRowAtIndexPath:index];


    cell.lbl_expiredtime.text=@"Hello";
    [cell.contentView bringSubviewToFront:cell.lbl_expiredtime];
}

I would define a method on the custom cell like so:

   - (void) updateMyLabel: (NSString *)newText   {
        // If the new value is different than what is already set, 
        // and the label isn't nil, then trigger the animation
        if (self.myLabel.text && self.myLabel.text != newText)    {
            [UIView animateWithDuration...];
        }
        self.myLabel.text = newText;
    }

Then call that method in your tableView's cellForRowAtIndexPath. The tricky thing is that cellForRowAtIndexPath can get called multiple times as the user scrolls around, or as data changes (ie every time you call reloadData).

I managed to get it to work by keeping track of the previous values held in myLabel.text .

I created an NSMutableDictionary on my viewController named previousStrings . With each key being an indexPath.row , and each value being a dictionary for that row.

Here's some code from inside cellForRow method.

NSMutableDictionary *strings;
// check to see if previousStrings already has a dictionary at key of indexPath.row
// if not, then create one.
if (![_previousStrings objectForKey:[NSString stringWithFormat:@"%d", indexPath.row]]) {
    strings = [[NSMutableDictionary alloc] init];
}
else {
    strings = [_previousStrings objectForKey:[NSString stringWithFormat:@"%d", indexPath.row]];
}

Then change myLabel.text

NSString *cellText = newTextString;
// If the new string is equal to the old string, just set the label without animation
// otherwise run animation and update the value inside the strings dictionary.
if ([strings[@"myLabel"] isEqualToString:newTextString]) {
    cell.myLabel.text = newTextString;
}
else {
    [cell.myLabel runTextChangeAnimationWithString:newTextString];
    [strings setObject:newTextString forKey:@"myLabel"];
}

After all that, at the end of cellForRow be sure to put the strings dict back into previousStrings

[_previousStrings setObject:strings forKey:[NSString stringWithFormat:@"%d", indexPath.row]];

I hope this makes sense for anyone else stumbling across the same issue. Feel free to edit and ask questions if it's not clear enough.

This is how the dictionaries are structured. Numbers being the indexPaths of each cell.

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM