【问题标题】:Making NSArray IBInspectable使 NSArray IBInspectable
【发布时间】:2015-06-24 22:21:20
【问题描述】:

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

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

我想做的是通过情节提要设置UIColorsNSArray 并在情节提要可视化期间在视图中绘制渐变层。

我开始创建名为 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];
}

【问题讨论】:

    标签: ios objective-c nsarray ibdesignable ibinspectable


    【解决方案1】:

    Xcode 自 7.1 版起不支持可检查数组。

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

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

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

    渐变视图.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
    

    渐变视图.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
    

    【讨论】:

    • 我不知道在drawRect中添加子层不是一个好习惯。谢谢你的建议。我认为它永远不会成为 Objective-C 中的一个特性(有时可能在 Swift 中),因为 NSArray 没有像在 Java 中使用菱形符号那样的类型。谢谢你的回答抢劫。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-17
    • 1970-01-01
    相关资源
    最近更新 更多