更好的解决方案:
问题是当UITableView 更改单元格的高度时,很可能是-beginUpdates 和-endUpdates。在 iOS 10 之前,size 和 origin 都会在单元格上播放动画。现在,在 iOS 10 GM 中,单元格将立即更改为新高度,然后将动画到正确的偏移量。
解决方案非常简单,带有约束。创建一个引导约束,它将更新它的高度,并将需要约束到单元格底部的其他视图现在约束到这个引导。
- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
UIView *heightGuide = [[UIView alloc] init];
heightGuide.translatesAutoresizingMaskIntoConstraints = NO;
[self.contentView addSubview:heightGuide];
[heightGuide addConstraint:({
self.heightGuideConstraint = [NSLayoutConstraint constraintWithItem:heightGuide attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:0.0f];
})];
[self.contentView addConstraint:({
[NSLayoutConstraint constraintWithItem:heightGuide attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f];
})];
UIView *anotherView = [[UIView alloc] init];
anotherView.translatesAutoresizingMaskIntoConstraints = NO;
anotherView.backgroundColor = [UIColor redColor];
[self.contentView addSubview:anotherView];
[anotherView addConstraint:({
[NSLayoutConstraint constraintWithItem:anotherView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1.0f constant:20.0f];
})];
[self.contentView addConstraint:({
[NSLayoutConstraint constraintWithItem:anotherView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f];
})];
[self.contentView addConstraint:({
// This is our constraint that used to be attached to self.contentView
[NSLayoutConstraint constraintWithItem:anotherView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:heightGuide attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f];
})];
[self.contentView addConstraint:({
[NSLayoutConstraint constraintWithItem:anotherView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self.contentView attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f];
})];
}
return self;
}
然后在需要时更新参考线高度。
- (void)setFrame:(CGRect)frame {
[super setFrame:frame];
if (self.window) {
[UIView animateWithDuration:0.3 animations:^{
self.heightGuideConstraint.constant = frame.size.height;
[self.contentView layoutIfNeeded];
}];
} else {
self.heightGuideConstraint.constant = frame.size.height;
}
}
请注意,将更新指南放在 -setFrame: 中可能不是最佳位置。到目前为止,我只构建了这个演示代码来创建解决方案。使用最终解决方案完成代码更新后,如果找到更好的放置位置,我将进行编辑。
原答案:
随着 iOS 10 测试版接近完成,希望这个问题将在下一个版本中得到解决。还有一个开放的错误报告。
我的解决方案涉及到图层的CAAnimation。这将检测高度的变化并自动设置动画,就像使用未链接到 UIView 的 CALayer 一样。
第一步是调整图层检测到变化时发生的情况。此代码必须在您的视图的子类中。该视图必须是您的tableViewCell.contentView 的子视图。在代码中,我们检查视图层的动作属性是否有我们动画的键。如果不只是打电话给超级。
- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {
return [layer.actions objectForKey:event] ?: [super actionForLayer:layer forKey:event];
}
接下来您要将动画添加到 actions 属性。您可能会发现此代码最好在视图位于窗口上并布局后应用。预先应用它可能会在视图移动到窗口时产生动画。
- (void)didMoveToWindow {
[super didMoveToWindow];
if (self.window) {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"bounds"];
self.layer.actions = @{animation.keyPath:animation};
}
}
就是这样!无需应用animation.duration,因为表格视图的-beginUpdates 和-endUpdates 会覆盖它。一般来说,如果您将此技巧用作应用动画的一种轻松方式,您将需要添加一个animation.duration,也许还需要添加一个animation.timingFunction。