【问题标题】:`CAGradientLayer` Define Start and End Points in Terms of Local Coordinate Space`CAGradientLayer` 根据局部坐标空间定义起点和终点
【发布时间】: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。层的梯度都是不同的。

【问题讨论】:

  • 结果如何?

标签: ios objective-c cocoa core-animation cagradientlayer


【解决方案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 的位置,无论视图有多大。等等,我加个像素。
  • 你去。如您所见,较大的视图尺寸“显示”了更多“底层”渐变,但两个视图的左上角是相同的 - 渐变本身是恒定的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-09-27
  • 2020-11-24
  • 2016-02-03
  • 1970-01-01
  • 2014-05-21
  • 2021-06-25
  • 1970-01-01
相关资源
最近更新 更多