I want to create a component for a UIButton subclass. To setup the button i want to set the image. My problem is I don't know how to make a CKComponentViewAttribute which takes the two arguments needed for UIButton method setImage:forState:
.
I tried this:
[CKComponent newWithView:{
[KGHitTestingButton class],
{
{CKComponentActionAttribute(@selector(onMenuTap))},
{@selector(setImage:forState:), [UIImage imageNamed:@"location_action"]}, @(UIControlStateNormal)},
}
} size:{.width = 30, .height = 30}]
But that won't compile. The same with this version:
{@selector(setImage:forState:), @[[UIImage imageNamed:@"location_action"]}, @(UIControlStateNormal)]},
}
I read here http://componentkit.org/docs/advanced-views.html that I need to box my inputs into a single object. How do I do that in this case?
Update: I found the following hint here https://github.com/facebook/componentkit/issues/265 :
"CKComponentViewAttribute can be initialized with an arbitrary block. Here's an example:
static const CKComponentViewAttribute titleShadowColorAttribute = {"MyComponent.titleShadowColor", ^(UIButton *button, id value){
[button setTitleShadowColor:value forState:UIControlStateNormal];
}};
"
And this is how I finally managed to solve my problem:
static const CKComponentViewAttribute imageAttribute = {"LocationActionButton.imageAttribute", ^(UIButton *button, id value){
[button setImage:value forState:UIControlStateNormal];
}};
CKComponent *locationActionButton = [CKComponent newWithView:{
[UIButton class],
{
{@selector(setBackgroundColor:), [UIColor redColor]},
{imageAttribute, [UIImage imageNamed:@"location_action"]}
}
} size:{.width = 30, .height = 30}];
You can do it inline to make it shorter:
CKComponent *locationActionButton = [CKComponent newWithView:{
[UIButton class],
{
{@selector(setBackgroundColor:), [UIColor redColor]},
{{"LocationActionButton.imageAttribute", ^(UIButton *button, id value){
[button setImage:value forState:UIControlStateNormal];
}}, [UIImage imageNamed:@"location_action"]}
}
} size:{.width = 30, .height = 30}];
One way you could solve this is to create a private category for the class that passes a collection with the arguments, and then applies then as expected. So something like:
@interface KGHitTestingButton (CKPrivate)
- (void)_ckSetImageforState:(NSArray*)args;
@end
@implementation
- (void)_ckSetImageforState:(NSArray*)args {
[self setImage:args[0] forState:[args[1] integerValue]];
}
@end
...
[CKComponent newWithView:{
[KGHitTestingButton class],
{
{@selector(_ckSetImageforState:), @[[UIImage imageNamed:@"location_action"]}, @(UIControlStateNormal)]},
}
...
It's not pretty, but it would work around this limitation. NSDictionary
would be an alternative, but would require defining some static keys.