Search code examples
iosasyncdisplaykit

Add padding around ASTextNode


I am working with AsyncDisplayKit (for the first time) and have an ASTextNode inside a ASCellNode. I want to adding padding or an inset around the text inside the ASTextNode. I attempted to wrap it with a ASDisplayNode but whenever I calculated it's size in calculateSizeThatFits: it always returned 0. Any suggestions would be appreciated. The code that is in the ASCellNode subclass is:

- (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
{
    CGSize textSize = [self.commentNode measure:CGSizeMake(constrainedSize.width - kImageSize - kImageToCommentPadding - kCellPadding - kInnerPadding, constrainedSize.height)];

    return CGSizeMake(constrainedSize.width, textSize.height);
}

- (void)layout
{
    self.imageNode.frame = CGRectMake(kCellPadding, kCellPadding, kImageSize, kImageSize);
    self.imageNode.layer.cornerRadius = kImageSize / 2.f;
    self.imageNode.layer.masksToBounds = YES;
    self.imageNode.layer.borderColor = [UIColor whiteColor].CGColor;
    self.imageNode.layer.borderWidth = 2.f;

    self.commentNode.backgroundColor = [UIColor whiteColor];
    self.commentNode.layer.cornerRadius = 8.f;
    self.commentNode.layer.masksToBounds = YES;

    CGSize textSize = self.commentNode.calculatedSize;
    self.commentNode.frame = CGRectMake(kCellPadding + kImageSize + kCellPadding, kCellPadding, textSize.width, textSize.height);
}

Solution

  • If you node is returning 0 height / size, you may be forgetting to invalidate its current size after changing its content.

    Use: [node invalidateCalculatedSize];

    For padding around the text node, you could add a node behind it with the size you want and then set a hitTestSlop on the text node. This would increase its tappable area.

    The better approach might be to embed it inside a custom node e.g.

    Interface

    @interface InsetTextNode: ASControlNode
    
    @property (nonatomic) UIEdgeInsets textInsets;
    @property (nonatomic) NSAttributedString * attributedString;
    @property ASTextNode * textNode;
    
    @end
    

    Implementation

    @implementation InsetTextNode
    
    - (instancetype)init
    {
        self = [super init];
        if (!self) return nil;
    
        [self addSubnode:textNode];
        self.textInsets = UIEdgeInsetsMake(8, 16, 8, 16);
    
        return self;
    }
    
    - (CGSize)calculateSizeThatFits:(CGSize)constrainedSize
    {
        CGFloat availableTextWidth = constrainedSize.width - self.textInsets.left - self.textInsets.right;
        CGFloat availableTextHeight = constrainedSize.height - self.textInsets.top - self.textInsets.bottom;
        CGSize constrainedTextSize = CGSizeMake(availableTextWidth, availableTextHeight);
    
        CGSize textSize = [self.textNode measure:constrainedTextSize];
    
        CGFloat finalWidth = self.textInsets.left + textSize.width + self.textInsets.right;
        CGFloat finalHeight = self.textInsets.top + textSize.height + self.textInsets.bottom;
    
        CGSize finalSize = CGSizeMake(finalWidth, finalHeight);
    
        return finalSize;
    }
    
    - (void)layout
    {
        CGFloat textX = self.textInsets.left;
        CGFloat textY = self.textInsets.top;
    
        CGSize textSize = self.textNode.calculatedSize;
    
        textNode.frame = CGRectMake(textX, textY, textSize.width, textSize.height);
    }
    
    - (NSAttributedString *) attributedString
    {
         return self.textNode.attributedString;
    }
    
    - (void)setAttributedString:(NSAttributedString *)attributedString
    {
        self.textNode.attributedString = attributedString;
        [self invalidateCalculatedSize];
    }
    
    - (void)setTextInsets:(UIEdgeInsets)textInsets
    {
        _textInsets = textInsets;
    
        [self invalidateCalculatedSize];
    }
    
    @end