In a constraint based view, there are several labels(top), buttons(bottom) and a customized UIView subclass (the checkers), which is consisted of many CALayers.
I am trying to animate the size of the view by removing and adding constraints:
// self.containerWidth is a constraint instance
// from Interface Builder Outlet, which is set to
// constrain the width of the whole view.
[self.calendarContainer removeConstraint:self.containerWidth];
[UIView animateWithDuration:4.0 animations:^{
[self.calendarContainer addConstraint:
[NSLayoutConstraint constraintWithItem:self.calendarContainer
attribute:NSLayoutAttributeWidth
relatedBy:NSLayoutRelationEqual
toItem:self.view
attribute:NSLayoutAttributeWidth
multiplier:0
constant:700]];
[self.calendarContainer layoutIfNeeded];
}];
After animation, the view looks as this:
During the animation, the labels(top) and buttons(bottom) were moving smoothly according to the duration given above, however, the checker view was bouncing very quickly to the final state before any other transitions occurred.
I suspect that there was something intermingled with some CATransaction implicitly.
In the checker view, I rearranged the frames of layers in -layoutSubviews
:
- (void)layoutSubviews {
[super layoutSubviews];
if (!self.layer.sublayers.count) {
[self prepareLayers];
}
int rowCount = [self rowCount];
CGFloat rowHeight = [self rowHeight];
[self.layer.sublayers enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
CALayer *rowLayer = obj;
NSNumber *rowIndex = [rowLayer valueForKey:@"rowindex"];
if (rowIndex) {
NSUInteger rowIndexValue = rowIndex.integerValue;
if (rowIndexValue < rowCount) {
rowLayer.hidden = NO;
rowLayer.frame = CGRectMake(0, rowHeight * rowIndexValue, self.frame.size.width, rowHeight);
[rowLayer.sublayers enumerateObjectsUsingBlock:^(id obj2, NSUInteger idx2, BOOL *stop2) {
CALayer *cellLayer = obj2;
NSUInteger colIndex = [[cellLayer valueForKey:@"cellindex"] integerValue] - rowIndexValue * 7 - 1;
cellLayer.frame = CGRectMake(colIndex*self.frame.size.width/7, 0, self.frame.size.width/7, rowHeight);
}];
} else {
// hide
rowLayer.hidden = YES;
}
}
}];
}
How can I correct these animations?
BTW, where is the most recommended place to insert these layer re-positioning code?
It seems that the effect was resulted from an implicit animation of layers.
The following code may fix all animation mismatches.
NSTimeInterval duration = 4.0;
[UIView animateWithDuration:duration animations:^{
[CATransaction begin];
[CATransaction setValue:@(duration)
forKey:kCATransactionAnimationDuration];
CAMediaTimingFunction *func = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
[CATransaction setAnimationTimingFunction:func];
[self.calendarContainer removeConstraint:self.containerWidth];
[self.calendarContainer addConstraint:[NSLayoutConstraint constraintWithItem:self.calendarContainer attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeWidth multiplier:0 constant:700]];
[self.calendarContainer layoutIfNeeded];
[CATransaction commit];
}];