Skip to content
This repository was archived by the owner on Feb 2, 2023. It is now read-only.

Commit ea6c7ae

Browse files
committed
Merge pull request #1025 from 1nput0utput/ASButtonNodeImprovements
[ASButtonNode] Add support for backgroundImage. Extend & simplify API with separate title and color.
2 parents eb7caa3 + 389945d commit ea6c7ae

2 files changed

Lines changed: 177 additions & 11 deletions

File tree

AsyncDisplayKit/ASButtonNode.h

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@
1111

1212
@interface ASButtonNode : ASControlNode
1313

14-
@property (nonatomic, readonly) ASTextNode *titleNode;
15-
@property (nonatomic, readonly) ASImageNode *imageNode;
14+
@property (nonatomic, readonly) ASTextNode * _Nonnull titleNode;
15+
@property (nonatomic, readonly) ASImageNode * _Nonnull imageNode;
16+
@property (nonatomic, readonly) ASImageNode * _Nonnull backgroundImageNode;
1617

1718
/**
1819
Spacing between image and title. Defaults to 8.0.
@@ -36,11 +37,66 @@
3637
*/
3738
@property (nonatomic, assign) ASVerticalAlignment contentVerticalAlignment;
3839

40+
/**
41+
* Returns the styled title associated with the specified state.
42+
*
43+
* @param state The state that uses the styled title. The possible values are described in ASControlState.
44+
*
45+
* @return The title for the specified state.
46+
*/
47+
- (NSAttributedString * _Nullable)attributedTitleForState:(ASControlState)state;
3948

40-
- (NSAttributedString *)attributedTitleForState:(ASControlState)state;
41-
- (void)setAttributedTitle:(NSAttributedString *)title forState:(ASControlState)state;
49+
/**
50+
* Sets the styled title to use for the specified state. This will reset styled title previously set with -setTitle:withFont:withColor:forState.
51+
*
52+
* @param title The styled text string to use for the title.
53+
* @param state The state that uses the specified title. The possible values are described in ASControlState.
54+
*/
55+
- (void)setAttributedTitle:(nullable NSAttributedString *)title forState:(ASControlState)state;
4256

43-
- (UIImage *)imageForState:(ASControlState)state;
44-
- (void)setImage:(UIImage *)image forState:(ASControlState)state;
57+
/**
58+
* Sets the title to use for the specified state. This will reset styled title previously set with -setAttributedTitle:forState.
59+
*
60+
* @param title The styled text string to use for the title.
61+
* @param font The font to use for the title.
62+
* @param color The color to use for the title.
63+
* @param state The state that uses the specified title. The possible values are described in ASControlState.
64+
*/
65+
- (void)setTitle:(nonnull NSString *)title withFont:(nullable UIFont *)font withColor:(nullable UIColor *)color forState:(ASControlState)state;
66+
67+
/**
68+
* Returns the image used for a button state.
69+
*
70+
* @param state The state that uses the image. Possible values are described in ASControlState.
71+
*
72+
* @return The image used for the specified state.
73+
*/
74+
- (UIImage * _Nullable)imageForState:(ASControlState)state;
75+
76+
/**
77+
* Sets the image to use for the specified state.
78+
*
79+
* @param image The image to use for the specified state.
80+
* @param state The state that uses the specified title. The values are described in ASControlState.
81+
*/
82+
- (void)setImage:(nullable UIImage *)image forState:(ASControlState)state;
83+
84+
/**
85+
* Sets the background image to use for the specified state.
86+
*
87+
* @param image The image to use for the specified state.
88+
* @param state The state that uses the specified title. The values are described in ASControlState.
89+
*/
90+
- (void)setBackgroundImage:(nullable UIImage *)image forState:(ASControlState)state;
91+
92+
93+
/**
94+
* Returns the background image used for a button state.
95+
*
96+
* @param state The state that uses the image. Possible values are described in ASControlState.
97+
*
98+
* @return The background image used for the specified state.
99+
*/
100+
- (UIImage * _Nullable)backgroundImageForState:(ASControlState)state;
45101

46102
@end

AsyncDisplayKit/ASButtonNode.mm

Lines changed: 115 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#import "ASStackLayoutSpec.h"
1111
#import "ASThread.h"
1212
#import "ASDisplayNode+Subclasses.h"
13+
#import "ASBackgroundLayoutSpec.h"
1314

1415
@interface ASButtonNode ()
1516
{
@@ -24,6 +25,11 @@ @interface ASButtonNode ()
2425
UIImage *_highlightedImage;
2526
UIImage *_selectedImage;
2627
UIImage *_disabledImage;
28+
29+
UIImage *_normalBackgroundImage;
30+
UIImage *_highlightedBackgroundImage;
31+
UIImage *_selectedBackgroundImage;
32+
UIImage *_disabledBackgroundImage;
2733
}
2834

2935
@end
@@ -41,33 +47,50 @@ - (instancetype)init
4147

4248
_titleNode = [[ASTextNode alloc] init];
4349
_imageNode = [[ASImageNode alloc] init];
50+
_backgroundImageNode = [[ASImageNode alloc] init];
51+
[_backgroundImageNode setContentMode:UIViewContentModeScaleToFill];
4452

53+
[_titleNode setLayerBacked:YES];
54+
[_imageNode setLayerBacked:YES];
55+
[_backgroundImageNode setLayerBacked:YES];
56+
4557
_contentHorizontalAlignment = ASAlignmentMiddle;
4658
_contentVerticalAlignment = ASAlignmentCenter;
4759

60+
[self addSubnode:_backgroundImageNode];
4861
[self addSubnode:_titleNode];
4962
[self addSubnode:_imageNode];
5063
}
5164
return self;
5265
}
5366

67+
- (void)setLayerBacked:(BOOL)layerBacked
68+
{
69+
ASDisplayNodeAssert(!layerBacked, @"ASButtonNode must not be layer backed!");
70+
[super setLayerBacked:layerBacked];
71+
}
72+
5473
- (void)setEnabled:(BOOL)enabled
5574
{
5675
[super setEnabled:enabled];
57-
[self updateImage];
58-
[self updateTitle];
76+
[self updateButtonContent];
5977
}
6078

6179
- (void)setHighlighted:(BOOL)highlighted
6280
{
6381
[super setHighlighted:highlighted];
64-
[self updateImage];
65-
[self updateTitle];
82+
[self updateButtonContent];
6683
}
6784

6885
- (void)setSelected:(BOOL)selected
6986
{
7087
[super setSelected:selected];
88+
[self updateButtonContent];
89+
}
90+
91+
- (void)updateButtonContent
92+
{
93+
[self updateBackgroundImage];
7194
[self updateImage];
7295
[self updateTitle];
7396
}
@@ -120,6 +143,27 @@ - (void)updateTitle
120143
}
121144
}
122145

146+
- (void)updateBackgroundImage
147+
{
148+
ASDN::MutexLocker l(_propertyLock);
149+
150+
UIImage *newImage;
151+
if (self.enabled == NO && _disabledBackgroundImage) {
152+
newImage = _disabledBackgroundImage;
153+
} else if (self.highlighted && _highlightedBackgroundImage) {
154+
newImage = _highlightedBackgroundImage;
155+
} else if (self.selected && _selectedBackgroundImage) {
156+
newImage = _selectedBackgroundImage;
157+
} else {
158+
newImage = _normalBackgroundImage;
159+
}
160+
161+
if (newImage != self.backgroundImageNode.image) {
162+
self.backgroundImageNode.image = newImage;
163+
[self setNeedsLayout];
164+
}
165+
}
166+
123167
- (CGFloat)contentSpacing
124168
{
125169
ASDN::MutexLocker l(_propertyLock);
@@ -152,6 +196,18 @@ - (void)setLaysOutHorizontally:(BOOL)laysOutHorizontally
152196
[self setNeedsLayout];
153197
}
154198

199+
- (void)setTitle:(NSString *)title withFont:(UIFont *)font withColor:(UIColor *)color forState:(ASControlState)state
200+
{
201+
NSDictionary *attributes = @{
202+
NSFontAttributeName: font ? font :[UIFont systemFontOfSize:[UIFont buttonFontSize]],
203+
NSForegroundColorAttributeName : color ? color : [UIColor blackColor]
204+
};
205+
206+
NSAttributedString *string = [[NSAttributedString alloc] initWithString:title
207+
attributes:attributes];
208+
[self setAttributedTitle:string forState:state];
209+
}
210+
155211
- (NSAttributedString *)attributedTitleForState:(ASControlState)state
156212
{
157213
ASDN::MutexLocker l(_propertyLock);
@@ -246,6 +302,54 @@ - (void)setImage:(UIImage *)image forState:(ASControlState)state
246302
[self updateImage];
247303
}
248304

305+
- (void)setBackgroundImage:(UIImage *)image forState:(ASControlState)state
306+
{
307+
ASDN::MutexLocker l(_propertyLock);
308+
switch (state) {
309+
case ASControlStateNormal:
310+
_normalBackgroundImage = image;
311+
break;
312+
313+
case ASControlStateHighlighted:
314+
_highlightedBackgroundImage = image;
315+
break;
316+
317+
case ASControlStateSelected:
318+
_selectedBackgroundImage = image;
319+
break;
320+
321+
case ASControlStateDisabled:
322+
_disabledBackgroundImage = image;
323+
break;
324+
325+
default:
326+
break;
327+
}
328+
[self updateBackgroundImage];
329+
}
330+
331+
- (UIImage *)backgroundImageForState:(ASControlState)state
332+
{
333+
ASDN::MutexLocker l(_propertyLock);
334+
switch (state) {
335+
case ASControlStateNormal:
336+
return _normalBackgroundImage;
337+
338+
case ASControlStateHighlighted:
339+
return _highlightedBackgroundImage;
340+
341+
case ASControlStateSelected:
342+
return _selectedBackgroundImage;
343+
344+
case ASControlStateDisabled:
345+
return _disabledBackgroundImage;
346+
347+
default:
348+
return _normalBackgroundImage;
349+
}
350+
351+
}
352+
249353
- (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
250354
{
251355
ASStackLayoutSpec *stack = [[ASStackLayoutSpec alloc] init];
@@ -265,12 +369,18 @@ - (ASLayoutSpec *)layoutSpecThatFits:(ASSizeRange)constrainedSize
265369

266370
stack.children = children;
267371

268-
return stack;
372+
if (self.backgroundImageNode.image) {
373+
return [ASBackgroundLayoutSpec backgroundLayoutSpecWithChild:stack
374+
background:self.backgroundImageNode];
375+
} else {
376+
return stack;
377+
}
269378
}
270379

271380
- (void)layout
272381
{
273382
[super layout];
383+
self.backgroundImageNode.hidden = self.backgroundImageNode.image == nil;
274384
self.imageNode.hidden = self.imageNode.image == nil;
275385
self.titleNode.hidden = self.titleNode.attributedString.length > 0 == NO;
276386
}

0 commit comments

Comments
 (0)