--- title: Implicit Hierarchy Management (Beta) layout: docs permalink: /docs/implicit-hierarchy-mgmt.html prevPage: batch-fetching-api.html nextPage: image-modification-block.html --- Enabling Implicit Hierarchy Management (IHM) is required to use the Layout Transition API. However, apps that don't require animations can still benefit from the reduction in code size that this feature enables. When enabled, IHM means that your nodes no longer require `addSubnode:` or `removeFromSupernode` method calls. The presence or absence of the IHM node _and_ its subnodes is completely determined in its `layoutSpecThatFits:` method. ### Enabling IHM ###
- (instancetype)initWithPhotoObject:(PhotoModel *)photo;
{
self = [super init];
if (self) {
_photoModel = photo;
_userAvatarImageNode = [[ASNetworkImageNode alloc] init];
_userAvatarImageNodeURL = photo.ownerUserProfile.userPicURL;
[self addSubnode:_userAvatarImageNode];
_photoImageNode = [[ASNetworkImageNode alloc] init];
_photoImageNode.URL = photo.URL;
[self addSubnode:_photoImageNode];
_userNameTextNode = [[ASTextNode alloc] init];
_userNameTextNode.attributedString = [photo.ownerUserProfile usernameAttributedStringWithFontSize:FONT_SIZE];
[self addSubnode:_userNameTextNode];
_photoLocationTextNode = [[ASTextNode alloc] init];
[photo.location reverseGeocodedLocationWithCompletionBlock:^(LocationModel *locationModel) {
if (locationModel == _photoModel.location) {
_photoLocationTextNode.attributedString = [photo locationAttributedStringWithFontSize:FONT_SIZE];
[self setNeedsLayout];
}
}];
[self addSubnode:_photoLocationTextNode];
}
return self;
}
`layoutSpecThatFits:` method.
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
{
ASStackLayoutSpec *headerSubStack = [ASStackLayoutSpec verticalStackLayoutSpec];
headerSubStack.flexShrink = YES;
if (_photoLocationLabel.attributedString) {
[headerSubStack setChildren:@[_userNameLabel, _photoLocationLabel]];
} else {
[headerSubStack setChildren:@[_userNameLabel]];
}
_userAvatarImageNode.preferredFrameSize = CGSizeMake(USER_IMAGE_HEIGHT, USER_IMAGE_HEIGHT); // constrain avatar image frame size
ASLayoutSpec *spacer = [[ASLayoutSpec alloc] init];
spacer.flexGrow = YES;
UIEdgeInsets avatarInsets = UIEdgeInsetsMake(HORIZONTAL_BUFFER, 0, HORIZONTAL_BUFFER, HORIZONTAL_BUFFER);
ASInsetLayoutSpec *avatarInset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:avatarInsets child:_userAvatarImageNode];
ASStackLayoutSpec *headerStack = [ASStackLayoutSpec horizontalStackLayoutSpec];
headerStack.alignItems = ASStackLayoutAlignItemsCenter; // center items vertically in horizontal stack
headerStack.justifyContent = ASStackLayoutJustifyContentStart; // justify content to the left side of the header stack
[headerStack setChildren:@[avatarInset, headerSubStack, spacer]];
// header inset stack
UIEdgeInsets insets = UIEdgeInsetsMake(0, HORIZONTAL_BUFFER, 0, HORIZONTAL_BUFFER);
ASInsetLayoutSpec *headerWithInset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:insets child:headerStack];
// footer inset stack
UIEdgeInsets footerInsets = UIEdgeInsetsMake(VERTICAL_BUFFER, HORIZONTAL_BUFFER, VERTICAL_BUFFER, HORIZONTAL_BUFFER);
ASInsetLayoutSpec *footerWithInset = [ASInsetLayoutSpec insetLayoutSpecWithInsets:footerInsets child:_photoCommentsNode];
// vertical stack
CGFloat cellWidth = constrainedSize.max.width;
_photoImageNode.preferredFrameSize = CGSizeMake(cellWidth, cellWidth); // constrain photo frame size
ASStackLayoutSpec *verticalStack = [ASStackLayoutSpec verticalStackLayoutSpec];
verticalStack.alignItems = ASStackLayoutAlignItemsStretch; // stretch headerStack to fill horizontal space
[verticalStack setChildren:@[headerWithInset, _photoImageNode, footerWithInset]];
return verticalStack;
}