CollectionViewCell 中的约束动画问题
Constraint Animation issue in CollectionViewCell
不幸的是,我仍然遇到约束问题......我绝对是我的问题,但我真的无法理解它们......
我创建了一个带有自定义单元格的 UICollectionView。
在单元格中,我插入了一个带有所有约束的 UIView。
Uiview 高度限制默认设置为零,并根据 collectionView 从 NSMutableArray 收集的数据进行更改
在 cellForItemAtIndexPath 方法中增加或减少自定义单元格中的 uiview 高度...
一切正常,数据收集完美,但我不明白为什么每次滚动 collectionView 时 uiview 高度动画都会继续..
我希望在显示 collectionView 时动画显示视图的高度,但在我向后或向前滚动时不显示...我创建了一个视频来向您展示此内容
我不明白我哪里错了,这些天我被一些问题困住了,我无法理解约束及其动画...
这是我正在使用的代码
主视图控制器
-(void)setupCollectionView {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.minimumLineSpacing = 2;
flowLayout.minimumInteritemSpacing = 0;
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_chartCollection = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
[_chartCollection registerClass:[KPHomeChartCell class] forCellWithReuseIdentifier:kChartCellIdentifier];
_chartCollection.backgroundColor = [UIColor clearColor];
_chartCollection.delegate = self;
_chartCollection.dataSource = self;
_chartCollection.pagingEnabled = YES;
_chartCollection.showsHorizontalScrollIndicator = NO;
_chartCollection.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_chartCollection];
self.topChartCollectionAnchor = [self.chartCollection.topAnchor constraintEqualToAnchor:self.customSwitch.bottomAnchor constant:20];
self.topChartCollectionAnchor.active = YES;
[self.chartCollection.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:30].active = YES;
[self.chartCollection.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[self.chartCollection.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-35].active = YES;
[self buildYAxis];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
KPHomeChartCell *chartCell = [collectionView dequeueReusableCellWithReuseIdentifier:kChartCellIdentifier forIndexPath:indexPath];
NSInteger n = [[self returnXAxis][indexPath.item] integerValue];
UILabel *yLabelValue = (UILabel *)[self viewWithTag:n];
chartCell.leftBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y;
chartCell.rightBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y +30;
return chartCell;
}
自定义 CollectionViewCell
-(void)animateHeightOfBarWithConstant {
// Crea la linea a tratti per ogni barra
CAShapeLayer *dashedLine = [CAShapeLayer layer];
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, nil, 0, 0);
CGPathAddLineToPoint(thePath, nil, 0, self.contentView.frame.size.height);
dashedLine.path = thePath;
CGPathRelease(thePath);
dashedLine.lineDashPattern = @[@4];
dashedLine.strokeColor = [UIColor colorWithHexString:@"#FFFFFF" setAlpha:.1].CGColor;
[self.contentView.layer addSublayer:dashedLine];
// BUILD BAR UIVIEW
_bar = [[UIView alloc] init];
_bar.layer.cornerRadius = 4;
_bar.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat barWidth = 15;
[self.contentView addSubview:_bar];
dispatch_async(dispatch_get_main_queue(), ^{
dashedLine.frame = CGRectMake(_bar.center.x, 0, self.contentView.frame.size.width , 15);
});
[self.bar.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES;
[self.bar.widthAnchor constraintEqualToConstant:barWidth].active = YES;
[self.bar.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-13.5].active = YES;
self.leftBarHeightConstraint = [self.bar.heightAnchor constraintEqualToConstant:0];
self.leftBarHeightConstraint.active = YES;
[UIView animateWithDuration:.9 animations:^{
[self.contentView layoutIfNeeded];
}];
}
如果仅 1. 外观需要动画,请执行以下操作:
- 在 viewDidAppear 中获取并保存当前时间(以秒为单位)NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];
- 在 cellForIndexPath if time of initial animation passed -> ([NSDate date] timeintervalSinceReferenceData] - startTime) > animationTime 将视图的大小设置为动画的最终状态(因此不会发生动画)
- 函数 animateHeightOfBarWithConstant() 应该有一个参数 (BOOL) 动画。如果设置为 YES,则执行动画(动画时间非零),如果发送 NO,则动画时间为 0 或使用 [UIView performWithoutAnimation:]
对单元格使用 -prepareForReuse() 方法。单元格被重复使用,您需要设置正确的开始条件或在 cellForIndexPath 方法中设置所有属性。
你可以试试这个代码
主视图控制器
@interface MainViewController () <UITableViewDelegate>
@property (nonatomic, assign) NSUInteger lastCellDisplayedIndex;
@end
@implementation MainViewController
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
_lastCellDisplayedIndex = indexPath.row;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
KPHomeChartCell *chartCell = [collectionView dequeueReusableCellWithReuseIdentifier:kChartCellIdentifier forIndexPath:indexPath];
NSInteger n = [[self returnXAxis][indexPath.item] integerValue];
UILabel *yLabelValue = (UILabel *)[self viewWithTag:n];
chartCell.leftBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y;
chartCell.rightBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y +30;
if (_lastCellDisplayedIndex >= indexPath) {
[chartCell updateHeightOfBarAnimated:NO];
} else {
[chartCell updateHeightOfBarAnimated:YES];
}
return chartCell;
}
@end
自定义 CollectionViewCell
-(void)updateHeightOfBarAnimated:(BOOL)animated {
// Crea la linea a tratti per ogni barra
CAShapeLayer *dashedLine = [CAShapeLayer layer];
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, nil, 0, 0);
CGPathAddLineToPoint(thePath, nil, 0, self.contentView.frame.size.height);
dashedLine.path = thePath;
CGPathRelease(thePath);
dashedLine.lineDashPattern = @[@4];
dashedLine.strokeColor = [UIColor colorWithHexString:@"#FFFFFF" setAlpha:.1].CGColor;
[self.contentView.layer addSublayer:dashedLine];
// BUILD BAR UIVIEW
_bar = [[UIView alloc] init];
_bar.layer.cornerRadius = 4;
_bar.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat barWidth = 15;
[self.contentView addSubview:_bar];
dispatch_async(dispatch_get_main_queue(), ^{
dashedLine.frame = CGRectMake(_bar.center.x, 0, self.contentView.frame.size.width , 15);
});
[self.bar.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES;
[self.bar.widthAnchor constraintEqualToConstant:barWidth].active = YES;
[self.bar.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-13.5].active = YES;
self.leftBarHeightConstraint = [self.bar.heightAnchor constraintEqualToConstant:0];
self.leftBarHeightConstraint.active = YES;
if (animated) {
[UIView animateWithDuration:.9 animations:^{
[self.contentView layoutIfNeeded];
}];
} else {
[self.contentView layoutIfNeeded];
}
}
- (void)prepareForReuse {
if (_bar) {
[_bar removeFromSuperview];
_bar = nil;
}
}
仅在 cellForItemAtIndexPath
中使用 updateHeightOfBarAnimated
不幸的是,我仍然遇到约束问题......我绝对是我的问题,但我真的无法理解它们......
我创建了一个带有自定义单元格的 UICollectionView。
在单元格中,我插入了一个带有所有约束的 UIView。
Uiview 高度限制默认设置为零,并根据 collectionView 从 NSMutableArray 收集的数据进行更改
在 cellForItemAtIndexPath 方法中增加或减少自定义单元格中的 uiview 高度...
一切正常,数据收集完美,但我不明白为什么每次滚动 collectionView 时 uiview 高度动画都会继续..
我希望在显示 collectionView 时动画显示视图的高度,但在我向后或向前滚动时不显示...我创建了一个视频来向您展示此内容
我不明白我哪里错了,这些天我被一些问题困住了,我无法理解约束及其动画...
这是我正在使用的代码
主视图控制器
-(void)setupCollectionView {
UICollectionViewFlowLayout *flowLayout = [[UICollectionViewFlowLayout alloc] init];
flowLayout.minimumLineSpacing = 2;
flowLayout.minimumInteritemSpacing = 0;
flowLayout.scrollDirection = UICollectionViewScrollDirectionHorizontal;
_chartCollection = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:flowLayout];
[_chartCollection registerClass:[KPHomeChartCell class] forCellWithReuseIdentifier:kChartCellIdentifier];
_chartCollection.backgroundColor = [UIColor clearColor];
_chartCollection.delegate = self;
_chartCollection.dataSource = self;
_chartCollection.pagingEnabled = YES;
_chartCollection.showsHorizontalScrollIndicator = NO;
_chartCollection.translatesAutoresizingMaskIntoConstraints = NO;
[self addSubview:_chartCollection];
self.topChartCollectionAnchor = [self.chartCollection.topAnchor constraintEqualToAnchor:self.customSwitch.bottomAnchor constant:20];
self.topChartCollectionAnchor.active = YES;
[self.chartCollection.leftAnchor constraintEqualToAnchor:self.leftAnchor constant:30].active = YES;
[self.chartCollection.rightAnchor constraintEqualToAnchor:self.rightAnchor].active = YES;
[self.chartCollection.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-35].active = YES;
[self buildYAxis];
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
KPHomeChartCell *chartCell = [collectionView dequeueReusableCellWithReuseIdentifier:kChartCellIdentifier forIndexPath:indexPath];
NSInteger n = [[self returnXAxis][indexPath.item] integerValue];
UILabel *yLabelValue = (UILabel *)[self viewWithTag:n];
chartCell.leftBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y;
chartCell.rightBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y +30;
return chartCell;
}
自定义 CollectionViewCell
-(void)animateHeightOfBarWithConstant {
// Crea la linea a tratti per ogni barra
CAShapeLayer *dashedLine = [CAShapeLayer layer];
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, nil, 0, 0);
CGPathAddLineToPoint(thePath, nil, 0, self.contentView.frame.size.height);
dashedLine.path = thePath;
CGPathRelease(thePath);
dashedLine.lineDashPattern = @[@4];
dashedLine.strokeColor = [UIColor colorWithHexString:@"#FFFFFF" setAlpha:.1].CGColor;
[self.contentView.layer addSublayer:dashedLine];
// BUILD BAR UIVIEW
_bar = [[UIView alloc] init];
_bar.layer.cornerRadius = 4;
_bar.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat barWidth = 15;
[self.contentView addSubview:_bar];
dispatch_async(dispatch_get_main_queue(), ^{
dashedLine.frame = CGRectMake(_bar.center.x, 0, self.contentView.frame.size.width , 15);
});
[self.bar.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES;
[self.bar.widthAnchor constraintEqualToConstant:barWidth].active = YES;
[self.bar.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-13.5].active = YES;
self.leftBarHeightConstraint = [self.bar.heightAnchor constraintEqualToConstant:0];
self.leftBarHeightConstraint.active = YES;
[UIView animateWithDuration:.9 animations:^{
[self.contentView layoutIfNeeded];
}];
}
如果仅 1. 外观需要动画,请执行以下操作:
- 在 viewDidAppear 中获取并保存当前时间(以秒为单位)NSTimeInterval startTime = [[NSDate date] timeIntervalSinceReferenceDate];
- 在 cellForIndexPath if time of initial animation passed -> ([NSDate date] timeintervalSinceReferenceData] - startTime) > animationTime 将视图的大小设置为动画的最终状态(因此不会发生动画)
- 函数 animateHeightOfBarWithConstant() 应该有一个参数 (BOOL) 动画。如果设置为 YES,则执行动画(动画时间非零),如果发送 NO,则动画时间为 0 或使用 [UIView performWithoutAnimation:]
对单元格使用 -prepareForReuse() 方法。单元格被重复使用,您需要设置正确的开始条件或在 cellForIndexPath 方法中设置所有属性。
你可以试试这个代码
主视图控制器
@interface MainViewController () <UITableViewDelegate>
@property (nonatomic, assign) NSUInteger lastCellDisplayedIndex;
@end
@implementation MainViewController
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
_lastCellDisplayedIndex = indexPath.row;
}
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(nonnull NSIndexPath *)indexPath {
KPHomeChartCell *chartCell = [collectionView dequeueReusableCellWithReuseIdentifier:kChartCellIdentifier forIndexPath:indexPath];
NSInteger n = [[self returnXAxis][indexPath.item] integerValue];
UILabel *yLabelValue = (UILabel *)[self viewWithTag:n];
chartCell.leftBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y;
chartCell.rightBarHeightConstraint.constant = [self offsetBarFromChart:collectionView] - yLabelValue.center.y +30;
if (_lastCellDisplayedIndex >= indexPath) {
[chartCell updateHeightOfBarAnimated:NO];
} else {
[chartCell updateHeightOfBarAnimated:YES];
}
return chartCell;
}
@end
自定义 CollectionViewCell
-(void)updateHeightOfBarAnimated:(BOOL)animated {
// Crea la linea a tratti per ogni barra
CAShapeLayer *dashedLine = [CAShapeLayer layer];
CGMutablePathRef thePath = CGPathCreateMutable();
CGPathMoveToPoint(thePath, nil, 0, 0);
CGPathAddLineToPoint(thePath, nil, 0, self.contentView.frame.size.height);
dashedLine.path = thePath;
CGPathRelease(thePath);
dashedLine.lineDashPattern = @[@4];
dashedLine.strokeColor = [UIColor colorWithHexString:@"#FFFFFF" setAlpha:.1].CGColor;
[self.contentView.layer addSublayer:dashedLine];
// BUILD BAR UIVIEW
_bar = [[UIView alloc] init];
_bar.layer.cornerRadius = 4;
_bar.translatesAutoresizingMaskIntoConstraints = NO;
CGFloat barWidth = 15;
[self.contentView addSubview:_bar];
dispatch_async(dispatch_get_main_queue(), ^{
dashedLine.frame = CGRectMake(_bar.center.x, 0, self.contentView.frame.size.width , 15);
});
[self.bar.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor].active = YES;
[self.bar.widthAnchor constraintEqualToConstant:barWidth].active = YES;
[self.bar.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor constant:-13.5].active = YES;
self.leftBarHeightConstraint = [self.bar.heightAnchor constraintEqualToConstant:0];
self.leftBarHeightConstraint.active = YES;
if (animated) {
[UIView animateWithDuration:.9 animations:^{
[self.contentView layoutIfNeeded];
}];
} else {
[self.contentView layoutIfNeeded];
}
}
- (void)prepareForReuse {
if (_bar) {
[_bar removeFromSuperview];
_bar = nil;
}
}
仅在 cellForItemAtIndexPath
updateHeightOfBarAnimated