From 6c56a6046b0a10d65abd75ecd737e57f03cb5ac9 Mon Sep 17 00:00:00 2001 From: Rajinder Ramgarhia Date: Sat, 16 Jan 2016 00:23:03 -0500 Subject: [PATCH 1/2] Simpler ASButtonNode API to set title and set background image --- AsyncDisplayKit/ASButtonNode.h | 68 ++++++++++++++++++-- AsyncDisplayKit/ASButtonNode.mm | 109 ++++++++++++++++++++++++++++++-- 2 files changed, 166 insertions(+), 11 deletions(-) diff --git a/AsyncDisplayKit/ASButtonNode.h b/AsyncDisplayKit/ASButtonNode.h index 588319b4b6..5ce7d966cc 100644 --- a/AsyncDisplayKit/ASButtonNode.h +++ b/AsyncDisplayKit/ASButtonNode.h @@ -11,8 +11,9 @@ @interface ASButtonNode : ASControlNode -@property (nonatomic, readonly) ASTextNode *titleNode; -@property (nonatomic, readonly) ASImageNode *imageNode; +@property (nonatomic, readonly) ASTextNode * _Nonnull titleNode; +@property (nonatomic, readonly) ASImageNode * _Nonnull imageNode; +@property (nonatomic, readonly) ASImageNode * _Nonnull backgroundImageNode; /** Spacing between image and title. Defaults to 8.0. @@ -36,11 +37,66 @@ */ @property (nonatomic, assign) ASVerticalAlignment contentVerticalAlignment; +/** + * Returns the styled title associated with the specified state. + * + * @param state The state that uses the styled title. The possible values are described in ASControlState. + * + * @return The title for the specified state. + */ +- (NSAttributedString * _Nullable)attributedTitleForState:(ASControlState)state; -- (NSAttributedString *)attributedTitleForState:(ASControlState)state; -- (void)setAttributedTitle:(NSAttributedString *)title forState:(ASControlState)state; +/** + * Sets the styled title to use for the specified state. + * + * @param title The styled text string to use for the title. + * @param state The state that uses the specified title. The possible values are described in ASControlState. + */ +- (void)setAttributedTitle:(nullable NSAttributedString *)title forState:(ASControlState)state; -- (UIImage *)imageForState:(ASControlState)state; -- (void)setImage:(UIImage *)image forState:(ASControlState)state; +/** + * Sets the title to use for the specified state. + * + * @param title The styled text string to use for the title. + * @param font The font to use for the title. + * @param color The color to use for the title. + * @param state The state that uses the specified title. The possible values are described in ASControlState. + */ +- (void)setTitle:(nonnull NSString *)title withFont:(nullable UIFont *)font withColor:(nullable UIColor *)color forState:(ASControlState)state; + +/** + * Returns the image used for a button state. + * + * @param state The state that uses the image. Possible values are described in ASControlState. + * + * @return The image used for the specified state. + */ +- (UIImage * _Nullable)imageForState:(ASControlState)state; + +/** + * Sets the image to use for the specified state. + * + * @param image The image to use for the specified state. + * @param state The state that uses the specified title. The values are described in ASControlState. + */ +- (void)setImage:(nullable UIImage *)image forState:(ASControlState)state; + +/** + * Sets the background image to use for the specified state. + * + * @param image The image to use for the specified state. + * @param state The state that uses the specified title. The values are described in ASControlState. + */ +- (void)setBackgroundImage:(nullable UIImage *)image forState:(ASControlState)state; + + +/** + * Returns the background image used for a button state. + * + * @param state The state that uses the image. Possible values are described in ASControlState. + * + * @return The background image used for the specified state. + */ +- (UIImage * _Nullable)backgroundImageForState:(ASControlState)state; @end diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 500d86271d..0dc3812f7a 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -10,6 +10,7 @@ #import "ASStackLayoutSpec.h" #import "ASThread.h" #import "ASDisplayNode+Subclasses.h" +#import "ASBackgroundLayoutSpec.h" @interface ASButtonNode () { @@ -24,6 +25,11 @@ UIImage *_highlightedImage; UIImage *_selectedImage; UIImage *_disabledImage; + + UIImage *_normalBackgroundImage; + UIImage *_highlightedBackgroundImage; + UIImage *_selectedBackgroundImage; + UIImage *_disabledBackgroundImage; } @end @@ -41,10 +47,12 @@ _titleNode = [[ASTextNode alloc] init]; _imageNode = [[ASImageNode alloc] init]; + _backgroundImageNode = [[ASImageNode alloc] init]; _contentHorizontalAlignment = ASAlignmentMiddle; _contentVerticalAlignment = ASAlignmentCenter; + [self addSubnode:_backgroundImageNode]; [self addSubnode:_titleNode]; [self addSubnode:_imageNode]; } @@ -54,20 +62,24 @@ - (void)setEnabled:(BOOL)enabled { [super setEnabled:enabled]; - [self updateImage]; - [self updateTitle]; + [self updateButtonContent]; } - (void)setHighlighted:(BOOL)highlighted { [super setHighlighted:highlighted]; - [self updateImage]; - [self updateTitle]; + [self updateButtonContent]; } - (void)setSelected:(BOOL)selected { [super setSelected:selected]; + [self updateButtonContent]; +} + +- (void)updateButtonContent +{ + [self updateBackgroundImage]; [self updateImage]; [self updateTitle]; } @@ -113,6 +125,27 @@ } } +- (void)updateBackgroundImage +{ + ASDN::MutexLocker l(_propertyLock); + + UIImage *newImage; + if (self.enabled == NO && _disabledBackgroundImage) { + newImage = _disabledBackgroundImage; + } else if (self.highlighted && _highlightedBackgroundImage) { + newImage = _highlightedBackgroundImage; + } else if (self.selected && _selectedBackgroundImage) { + newImage = _selectedBackgroundImage; + } else { + newImage = _normalBackgroundImage; + } + + if (newImage != self.backgroundImageNode.image) { + self.backgroundImageNode.image = newImage; + [self setNeedsLayout]; + } +} + - (CGFloat)contentSpacing { ASDN::MutexLocker l(_propertyLock); @@ -145,6 +178,18 @@ [self setNeedsLayout]; } +- (void)setTitle:(NSString *)title withFont:(UIFont *)font withColor:(UIColor *)color forState:(ASControlState)state +{ + NSDictionary *attributes = @{ + NSFontAttributeName: font ? font :[UIFont systemFontOfSize:[UIFont buttonFontSize]], + NSForegroundColorAttributeName : color ? color : [UIColor blackColor] + }; + + NSAttributedString *string = [[NSAttributedString alloc] initWithString:title + attributes:attributes]; + [self setAttributedTitle:string forState:state]; +} + - (NSAttributedString *)attributedTitleForState:(ASControlState)state { ASDN::MutexLocker l(_propertyLock); @@ -239,6 +284,54 @@ [self updateImage]; } +- (void)setBackgroundImage:(UIImage *)image forState:(ASControlState)state +{ + ASDN::MutexLocker l(_propertyLock); + switch (state) { + case ASControlStateNormal: + _normalBackgroundImage = image; + break; + + case ASControlStateHighlighted: + _highlightedBackgroundImage = image; + break; + + case ASControlStateSelected: + _selectedBackgroundImage = image; + break; + + case ASControlStateDisabled: + _disabledBackgroundImage = image; + break; + + default: + break; + } + [self updateBackgroundImage]; +} + +- (UIImage *)backgroundImageForState:(ASControlState)state +{ + ASDN::MutexLocker l(_propertyLock); + switch (state) { + case ASControlStateNormal: + return _normalBackgroundImage; + + case ASControlStateHighlighted: + return _highlightedBackgroundImage; + + case ASControlStateSelected: + return _selectedBackgroundImage; + + case ASControlStateDisabled: + return _disabledBackgroundImage; + + default: + return _normalBackgroundImage; + } + +} + - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize { ASStackLayoutSpec *stack = [[ASStackLayoutSpec alloc] init]; @@ -258,12 +351,18 @@ stack.children = children; - return stack; + if (self.backgroundImageNode.image) { + return [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:stack + background:self.backgroundImageNode]; + } else { + return stack; + } } - (void)layout { [super layout]; + self.backgroundImageNode.hidden = self.backgroundImageNode.image == nil; self.imageNode.hidden = self.imageNode.image == nil; self.titleNode.hidden = self.titleNode.attributedString.length > 0 == NO; } From 389945d69d4f8e3f18557322e28fa82338ca8e05 Mon Sep 17 00:00:00 2001 From: Rajinder Ramgarhia Date: Wed, 20 Jan 2016 14:29:34 -0500 Subject: [PATCH 2/2] ASButtonNode sets its subnodes as layer backed, but itelf should not be layer backed --- AsyncDisplayKit/ASButtonNode.h | 4 ++-- AsyncDisplayKit/ASButtonNode.mm | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/AsyncDisplayKit/ASButtonNode.h b/AsyncDisplayKit/ASButtonNode.h index 5ce7d966cc..305121b3a6 100644 --- a/AsyncDisplayKit/ASButtonNode.h +++ b/AsyncDisplayKit/ASButtonNode.h @@ -47,7 +47,7 @@ - (NSAttributedString * _Nullable)attributedTitleForState:(ASControlState)state; /** - * Sets the styled title to use for the specified state. + * Sets the styled title to use for the specified state. This will reset styled title previously set with -setTitle:withFont:withColor:forState. * * @param title The styled text string to use for the title. * @param state The state that uses the specified title. The possible values are described in ASControlState. @@ -55,7 +55,7 @@ - (void)setAttributedTitle:(nullable NSAttributedString *)title forState:(ASControlState)state; /** - * Sets the title to use for the specified state. + * Sets the title to use for the specified state. This will reset styled title previously set with -setAttributedTitle:forState. * * @param title The styled text string to use for the title. * @param font The font to use for the title. diff --git a/AsyncDisplayKit/ASButtonNode.mm b/AsyncDisplayKit/ASButtonNode.mm index 0dc3812f7a..c0abfe11ca 100644 --- a/AsyncDisplayKit/ASButtonNode.mm +++ b/AsyncDisplayKit/ASButtonNode.mm @@ -48,7 +48,12 @@ _titleNode = [[ASTextNode alloc] init]; _imageNode = [[ASImageNode alloc] init]; _backgroundImageNode = [[ASImageNode alloc] init]; + [_backgroundImageNode setContentMode:UIViewContentModeScaleToFill]; + [_titleNode setLayerBacked:YES]; + [_imageNode setLayerBacked:YES]; + [_backgroundImageNode setLayerBacked:YES]; + _contentHorizontalAlignment = ASAlignmentMiddle; _contentVerticalAlignment = ASAlignmentCenter; @@ -59,6 +64,12 @@ return self; } +- (void)setLayerBacked:(BOOL)layerBacked +{ + ASDisplayNodeAssert(!layerBacked, @"ASButtonNode must not be layer backed!"); + [super setLayerBacked:layerBacked]; +} + - (void)setEnabled:(BOOL)enabled { [super setEnabled:enabled];