What is the correlation between bounds.size and frame.size when animating UICollectionViewCell

倖福魔咒の 提交于 2019-12-22 08:38:44

问题


I've read on several posts (like https://stackoverflow.com/a/5340339/1084822 and https://stackoverflow.com/a/15582466/1084822) that to resize a UIView with animation, we can't animate the frame and we must do it with a mix of bounds.size, bounds.origin and position.

However, I can't find what is the correlation between those properties and those of the frame.

I have a UICollectionView with a custom layout. When a cell is deleted, the layout is refreshed and every cell gets its new frame through the prepareLayout and layoutAttributesForElementsInRect: methods. Then, the finalizeCollectionViewUpdates method (where we can edit animations) gets called and finally the cells move and get resized.

I've done a lot of exploration by trial and error with the cells animation and here is what I found :

  • 3 animations are set by default to my visible cells which are position, bounds.origin and bounds.size
  • when I change the from/to values of these animations, only the POSITION of the cell is affected, and never its SIZE

Detailed results

Default values

When I stick to the default values of the animations and check their values with these logs,

- (void)finalizeCollectionViewUpdates {
    for(UICollectionViewCell* cell in [self.collectionView visibleCells]) {
        NSLog(@"cell: %@", cell);
        for(NSString* key in cell.layer.animationKeys) {
            CABasicAnimation* animation = (CABasicAnimation*)[cell.layer animationForKey:key];
            NSLog(@"animation %@: from %@ to %@", key, animation.fromValue, animation.toValue);
        }
    }
}

I get this for the shrinking cell (its frame represent its final state):

cell: <PlayQueueSongCell: 0x7fbf1bc8ebe0; baseClass = UICollectionViewCell; frame = (53.3333 80; 480 480); opaque = NO; animations = { position=<CABasicAnimation: 0x7fbf1bf54e20>; bounds.origin=<CABasicAnimation: 0x7fbf1bf556b0>; bounds.size=<CABasicAnimation: 0x7fbf1bf557a0>; }; layer = <CALayer: 0x7fbf1bc8e9f0>>
animation position: from NSPoint: {666.66666666666674, 0} to NSPoint: {0, 0}
animation bounds.origin: from NSPoint: {0, 0} to NSPoint: {0, 0}
animation bounds.size: from NSSize: {160, 160} to NSSize: {0, 0}

and this for the expending cell (its frame represent its final state):

cell: <PlayQueueSongCell: 0x7fbf1bd6cd00; baseClass = UICollectionViewCell; frame = (640 0; 640 640); opaque = NO; animations = { position=<CABasicAnimation: 0x7fbf1bf55b70>; bounds.origin=<CABasicAnimation: 0x7fbf1bf55e20>; bounds.size=<CABasicAnimation: 0x7fbf1bf55f10>; }; layer = <CALayer: 0x7fbf1bd73200>>
animation position: from NSPoint: {666.66666666666652, 0} to NSPoint: {0, 0}
animation bounds.origin: from NSPoint: {0, 0} to NSPoint: {0, 0}
animation bounds.size: from NSSize: {-160, -160} to NSSize: {0, 0}

See the result in slow motion:

No bounds.size animation

When I remove the bounds.size animation with this block of code,

- (void)finalizeCollectionViewUpdates {
    for(UICollectionViewCell* cell in [self.collectionView visibleCells]) {
        for(NSString* key in cell.layer.animationKeys) {
            [cell.layer removeAnimationForKey:@"bounds.size"];
        }
    }
}

I can see that only the POSITION of the cell is affected...

bounds.size animation from (0,0) to (1000,1000)

And when I change the values of bounds.size to (0,0) -> (1000,1000) with this block of code:

- (void)finalizeCollectionViewUpdates {
    for(UICollectionViewCell* cell in [self.collectionView visibleCells]) {
        for(NSString* key in cell.layer.animationKeys) {
            [cell.layer removeAnimationForKey:@"bounds.size"];
            CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds.size"];
            [animation setFromValue:[NSValue valueWithCGSize:CGSizeZero]];
            [animation setToValue:[NSValue valueWithCGSize:CGSizeMake(1000, 1000)]];
            [animation setDuration:0.3];
            [cell.layer addAnimation:animation forKey:@"bounds.size"];
        }
    }
}

I can still see that only the POSITION of the cell is affected...

Question

Since the cell gets its new frame just before the animation starts and the bounds.size does not affect the cell's size, I can't find a way to change its size smoothly.

What is the correlation between the bounds.size and the frame.size that everyone is talking about and how can one animate the size of the cell?


回答1:


The solution I found is to first remove the bounds.size animation since it moves the cell in an unwanted way. Then, I create a transform.scale animation that starts with a value that will simulate its previous size and stops with a value of 1.

if([cell.layer animationForKey:@"bounds.size"]) {
    [cell.layer removeAnimationForKey:@"bounds.size"];

    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.scale"];
    animation.duration = 0.3;
    if(CGSizeEqualToSize(cell.frame.size, self.itemSize)) { //shrinking cell
        animation.fromValue = @1.333;
        animation.toValue = @1;
    } else {                                                //expending cell
        animation.fromValue = @0.75;
        animation.toValue = @1;
    }
    [cell.layer addAnimation:animation forKey:@"transform.scale"];
}


来源:https://stackoverflow.com/questions/35140258/what-is-the-correlation-between-bounds-size-and-frame-size-when-animating-uicoll

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!