Xcode doesn't support inspectable arrays as of version 7.1.
You can cheese it for a gradient layer if you pick a maximum number of gradient stops. Here's what my test looks like, where I hardcoded six stops:
Incidentally, you shouldn't add subviews or sublayers in drawRect:
. The system doesn't expect updates to the layer hierarchy at that stage. You should do it in layoutSubviews
.
Here's the code I used to create that screen shot.
GradientView.h
#import <UIKit/UIKit.h>
IB_DESIGNABLE
@interface GradientView : UIView
@property(nonatomic, readonly, strong) CAGradientLayer *layer;
@property (nonatomic) IBInspectable CGPoint startPoint;
@property (nonatomic) IBInspectable CGPoint endPoint;
@property (nonatomic, strong) IBInspectable UIColor *color0;
@property (nonatomic) IBInspectable CGFloat location0;
@property (nonatomic, strong) IBInspectable UIColor *color1;
@property (nonatomic) IBInspectable CGFloat location1;
@property (nonatomic, strong) IBInspectable UIColor *color2;
@property (nonatomic) IBInspectable CGFloat location2;
@property (nonatomic, strong) IBInspectable UIColor *color3;
@property (nonatomic) IBInspectable CGFloat location3;
@property (nonatomic, strong) IBInspectable UIColor *color4;
@property (nonatomic) IBInspectable CGFloat location4;
@property (nonatomic, strong) IBInspectable UIColor *color5;
@property (nonatomic) IBInspectable CGFloat location5;
@end
GradientView.m
#import "GradientView.h"
#define MaxStops 6
typedef struct {
CGColorRef color;
CGFloat location;
} GradientStop;
@implementation GradientView
@dynamic layer;
- (void)setStartPoint:(CGPoint)startPoint {
self.layer.startPoint = startPoint;
}
- (CGPoint)startPoint {
return self.layer.startPoint;
}
- (void)setEndPoint:(CGPoint)endPoint {
self.layer.endPoint = endPoint;
}
- (CGPoint)endPoint {
return self.layer.endPoint;
}
#define DefineSetters(i) \
- (void)setColor##i:(UIColor *)color##i { \
_color##i = color##i; \
[self setNeedsLayout]; \
} \
\
- (void)setLocation##i:(CGFloat)location##i { \
_location##i = location##i; \
[self setNeedsLayout]; \
}
DefineSetters(0)
DefineSetters(1)
DefineSetters(2)
DefineSetters(3)
DefineSetters(4)
DefineSetters(5)
+ (Class)layerClass {
return [CAGradientLayer class];
}
- (void)layoutSubviews {
[super layoutSubviews];
[self updateGradient];
}
static BOOL isValidStop(const GradientStop *stop) {
return stop->color != nil && stop->location >= 0 && stop->location <= 1;
}
static int compareStops(const void *a, const void *b) {
const GradientStop *stop0 = a;
const GradientStop *stop1 = b;
if (isValidStop(stop0) && isValidStop(stop1)) {
if (stop0->location < stop1->location) {
return -1;
} else if (stop0->location > stop1->location) {
return 1;
} else {
return 0;
}
} else if (isValidStop(stop0)) {
return -1;
} else if (isValidStop(stop1)) {
return 1;
} else {
return 0;
}
}
static size_t countOfValidStops(const GradientStop *stops, size_t maxStops) {
for (size_t i = 0; i < maxStops; ++i) {
if (!isValidStop(&stops[i])) {
return i;
}
}
return maxStops;
}
- (void)updateGradient {
GradientStop stops[MaxStops];
[self setStop:stops+0 color:self.color0 location:self.location0];
[self setStop:stops+1 color:self.color1 location:self.location1];
[self setStop:stops+2 color:self.color2 location:self.location2];
[self setStop:stops+3 color:self.color3 location:self.location3];
[self setStop:stops+4 color:self.color4 location:self.location4];
[self setStop:stops+5 color:self.color5 location:self.location5];
qsort(stops, MaxStops, sizeof *stops, compareStops);
size_t count = countOfValidStops(stops, MaxStops);
NSMutableArray *colors = [NSMutableArray arrayWithCapacity:count];
NSMutableArray *locations = [NSMutableArray arrayWithCapacity:count];
[self populateColors:colors locations:locations fromStops:stops count:count];
self.layer.colors = colors;
self.layer.locations = locations;
}
- (void)setStop:(GradientStop *)stop color:(UIColor *)color location:(CGFloat)location {
stop->color = color.CGColor;
stop->location = location;
}
- (void)populateColors:(NSMutableArray *)colors locations:(NSMutableArray *)locations fromStops:(const GradientStop *)stops count:(size_t)count {
for (size_t i = 0; i < count; ++i) {
[colors addObject:(__bridge id)stops[i].color];
[locations addObject:@(stops[i].location)];
}
}
@end