`CAGradientLayer` 根据局部坐标空间定义起点和终点

Posted

技术标签:

【中文标题】`CAGradientLayer` 根据局部坐标空间定义起点和终点【英文标题】:`CAGradientLayer` Define Start and End Points in Terms of Local Coordinate Space 【发布时间】:2015-05-06 17:16:57 【问题描述】:

CAGradientLayer 有两个属性 startPointendPoint。这些属性是根据单位坐标空间定义的。结果是,如果我有两个具有相同起点和终点且边界不同的渐变层,这两个渐变将是不同的。

CAGradientLayer 层的startPointendPoint 如何不根据单位坐标空间而是根据标准点坐标来定义,以便渐变的角度/大小不受边界的影响层?

理想的结果是渐变层可以调整为任何大小或形状,并且渐变保持在原位,尽管裁剪不同。


资格: 我知道这似乎是坐标空间之间的一个绝对微不足道的转换,但显然,是的,我实际上就是那么愚蠢,或者CAGradientLayers 的工作方式可能存在一些问题或非常违反直觉。我没有提供我期望的正确方法的示例,因为(假设我只是愚蠢)它只会误导。


编辑:

这是我对 CALayer 的实现,它添加了一个子 CAGradientLayer 并配置它的起点和终点。它不会产生预期的结果。

@interface MyLayer ()
@property (nonatomic, strong) CAGradientLayer *gradientLayer;
@end

@implementation MyLayer

- (instancetype)init 
    if (self = [super init]) 
        self.gradientLayer = [CAGradientLayer new];
        [self addSublayer:self.gradientLayer];
        self.gradientLayer.colors = @[ (id)[UIColor redColor].CGColor,  (id)[UIColor orangeColor].CGColor, (id)[UIColor greenColor].CGColor, (id)[UIColor blueColor].CGColor];;
        self.gradientLayer.locations = @[ @0, @.333, @.666, @1 ];
    
    return self;


- (void)layoutSublayers 
    [super layoutSublayers];
    self.gradientLayer.frame = self.bounds;
    self.gradientLayer.startPoint = CGPointMake(0, 0);
    self.gradientLayer.endPoint = CGPointMake(100 / self.bounds.size.width, 40 / self.bounds.size.height);


@end

我有一个 .xib 文件,其中包含许多不同大小的 MyLayer。层的梯度都是不同的。

【问题讨论】:

结果如何? 【参考方案1】:

否则您无法定义 startPoint 和 endPoint。你有两个选择:

根据视图高度计算这些值(50 像素,100 像素视图高度 = 0.5,100 像素视图高度 = 0.25)

以所需的最大固定大小创建渐变(例如:高度为 568),并将其添加为另一个视图的子视图,该视图将根据您的需要调整大小,启用 clipsToBounds。这样,您就可以实现您想要的(让渐变始终从顶部开始并剪切底部,保持渐变居中并剪切顶部和底部等)

【讨论】:

是的。正如您所指出的,该功能不能直接在渐变层上使用,但创建一个包装器或子类并执行您提到的转换会同样好。问题是,让这些转换按照您的描述进行工作证明比我预期的要困难。 使用更大的剪裁渐变也可以,但您的第一个策略似乎是正确的。它看起来更有效率和可扩展性。 第二种策略的优势在于您可以确保使用相同的渐变。第一种是更“轻量级”和简单,但计算比例会带来四舍五入造成的差异。 我没有考虑过渲染中的差异。这是一个有趣的可能性,如果层是……分层的,这可能是一个问题。除此之外,您能否获得第一个解决方案的有效实施?尝试实施它时,我得到了奇怪的结果。【参考方案2】:

如何不根据单位坐标空间而是根据标准点坐标来定义 CAGradientLayer 图层的起点和终点,以使渐变的角度/大小不受图层边界的影响?

不能。但是你可以很容易地想到一个不同的策略。例如:

以不同的方式绘制渐变(使用 Quartz 而不是依靠 CAGradientLayer 为您绘制)。

使用蒙版使图层显示为一定的大小和形状,您可以通过更改蒙版来更改该大小和形状,但实际上图层本身就是一个大始终具有相同渐变的恒定大小的图层。

检测到梯度层改变了边界,改变梯度startPointendPoint匹配。这是一个视图的工作示例,其图层是渐变图层并执行此操作 - 但您必须记住每次边界更改时都重新绘制图层!

override func drawLayer(layer: CALayer!, inContext ctx: CGContext!) 
    let grad = layer as! CAGradientLayer
    grad.colors = [UIColor.whiteColor().CGColor, UIColor.redColor().CGColor]
    let maxx:CGFloat = 500.0 // or whatever
    let maxy:CGFloat = 500.0 // or whatever
    grad.startPoint = CGPointMake(0,0) // or whatever!
    grad.endPoint = CGPointMake(maxx/self.bounds.width, maxy/self.bounds.height)

【讨论】:

您的第一个选项几乎完全符合我尝试的实现,但是不同层上的渐变都是不同的。这段代码对你来说表现正确吗? 取决于“正确”的含义。我不会更改startPoint,但显然我也可以这样做!你也可以。因此,例如,如果需要,我们可以将虚拟起点设为超级视图的左上角。 当然,其他细节也可以实现。但是无论图层的大小如何,您确实看到了 (500, 500) 的终点?在我自己的测试项目中,我有许多不同大小/形状的图层,它们实现了类似的东西,而且图层的大小不可思议地影响了渐变。 是的,终点在屏幕左侧下方,即 500,500 的位置,无论视图有多大。等等,我加个像素。 你去。如您所见,较大的视图尺寸“显示”了更多“底层”渐变,但两个视图的左上角是相同的 - 渐变本身是恒定的。

以上是关于`CAGradientLayer` 根据局部坐标空间定义起点和终点的主要内容,如果未能解决你的问题,请参考以下文章

iOS中利用CAGradientLayer绘制渐变色的方法实例

CAGradientLayer的一些属性解析

CAGradientLayer渐变效果

CAGradientLayer 类型——有啥意义?

在动态大小的 UITableViewCell 上应用 CAGradientLayer

对象坐标上的旋转和平移