ios - 使 NSArray IBInspectable

标签 ios objective-c nsarray ibdesignable ibinspectable

有没有办法使用 NSArray IBInspectable 来在 Storyboard 自定义 View 中定义多个值?

我知道 NSArray 没有任何关于将存储在其中的对象类型的信息,所以这可能是一个问题。但是有一些使用注释或其他东西的解决方案吗?

我想做的是通过 Storyboard 设置 UIColorsNSArray,并在 Storyboard 可视化期间在 View 中绘制渐变图层。

我开始创建两个名为 startColor 和 endColor 的属性。这很好用,但我想做的更通用。

这是我的 drawRect 方法:

- (void)drawRect:(CGRect)rect {
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    
    gradientLayer.frame = self.bounds;
    
    gradientLayer.colors = [NSArray arrayWithObjects:(id)[self.startColor CGColor], (id)[self.endColor CGColor], nil];
    
    [self.layer addSublayer:gradientLayer];
}

我想做这样的事情:

- (void)drawRect:(CGRect)rect {
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    
    gradientLayer.frame = self.bounds;
    
    // colorsArray should be an IBInspectable property in order to be setted on Storyboard Attributes Inspector
    gradientLayer.colors = self.colorsArray;
    
    [self.layer addSublayer:gradientLayer];
}

最佳答案

从 7.1 版开始,Xcode 不支持可检查数组。

如果您选择了最大数量的渐变停止点,则可以将其用于渐变层。这是我的测试的样子,我在其中硬编码了六个停止点:

screen shot of designable gradient view

顺便说一句,您不应该在drawRect: 中添加 subview 或子层。系统不希望在那个阶段更新图层层次结构。您应该在 layoutSubviews 中完成。

这是我用来创建该屏幕截图的代码。

渐变 View .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

渐变 View .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

关于ios - 使 NSArray IBInspectable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29709818/

相关文章:

开发模式下的 iOS 游戏中心

ios - NSDate dateWithTimeIntervalSince1970 添加额外的一天

objective-c - Realm 迁移竞争条件

objective-c - 在 ARC 下,如何释放 NSArray 中的元素?

ios - 如何从 nsarray 的 nsarray 中搜索特定联系人

ios - 逐个迭代格式 % 占位符

ios - 使用 @State 变量属性作为绑定(bind)

swift - 在 swift 中对成员 'joinWithSeparator' 的引用不明确

json - Swift 2 中的 HTTP 请求和条件

iphone - objective-c ARC 只读属性和私有(private) setter 实现