--- title: Layout Transition API layout: docs permalink: /docs/layout-transition-api.html prevPage: layout2-api-sizing.html nextPage: hit-test-slop.html --- The Layout Transition API was designed to make all animations with Texture easy - even transforming an entire set of views into a completely different set of views! With this system, you simply specify the desired layout and Texture will do the work to figure out differences from the current layout. It will automatically add new elements, remove unneeded elements after the transition, and update the position of any existing elements. There are also easy to use APIs that allow you to fully customize the starting position of newly introduced elements, as well as the ending position of removed elements.
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
FieldNode *field;
if (self.fieldState == SignupNodeName) {
field = self.nameField;
} else {
field = self.ageField;
}
ASStackLayoutSpec *stack = [[ASStackLayoutSpec alloc] init];
[stack setChildren:@[field, self.buttonNode]];
UIEdgeInsets insets = UIEdgeInsetsMake(15.0, 15.0, 15.0, 15.0);
return [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:stack];
}
self.signupNode.fieldState = SignupNodeAge;
[self.signupNode transitionLayoutWithAnimation:YES];
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context
{
if (self.fieldState == SignupNodeName) {
CGRect initialNameFrame = [context initialFrameForNode:self.ageField];
initialNameFrame.origin.x += initialNameFrame.size.width;
self.nameField.frame = initialNameFrame;
self.nameField.alpha = 0.0;
CGRect finalAgeFrame = [context finalFrameForNode:self.nameField];
finalAgeFrame.origin.x -= finalAgeFrame.size.width;
[UIView animateWithDuration:0.4 animations:^{
self.nameField.frame = [context finalFrameForNode:self.nameField];
self.nameField.alpha = 1.0;
self.ageField.frame = finalAgeFrame;
self.ageField.alpha = 0.0;
} completion:^(BOOL finished) {
[context completeTransition:finished];
}];
} else {
CGRect initialAgeFrame = [context initialFrameForNode:self.nameField];
initialAgeFrame.origin.x += initialAgeFrame.size.width;
self.ageField.frame = initialAgeFrame;
self.ageField.alpha = 0.0;
CGRect finalNameFrame = [context finalFrameForNode:self.ageField];
finalNameFrame.origin.x -= finalNameFrame.size.width;
[UIView animateWithDuration:0.4 animations:^{
self.ageField.frame = [context finalFrameForNode:self.ageField];
self.ageField.alpha = 1.0;
self.nameField.frame = finalNameFrame;
self.nameField.alpha = 0.0;
} completion:^(BOOL finished) {
[context completeTransition:finished];
}];
}
}
- (void)animateLayoutTransition:(id<ASContextTransitioning>)context
{
if ([context isAnimated]) {
// perform animation
} else {
[super animateLayoutTransition:context];
}
}
- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
{
[super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
[coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) {
[self.node transitionLayoutWithSizeRange:ASSizeRangeMake(size, size) animated:YES];
} completion:nil];
}