`CAGradientLayer` 根据局部坐标空间定义起点和终点
Posted
技术标签:
【中文标题】`CAGradientLayer` 根据局部坐标空间定义起点和终点【英文标题】:`CAGradientLayer` Define Start and End Points in Terms of Local Coordinate Space 【发布时间】:2015-05-06 17:16:57 【问题描述】:CAGradientLayer
有两个属性 startPoint
和 endPoint
。这些属性是根据单位坐标空间定义的。结果是,如果我有两个具有相同起点和终点且边界不同的渐变层,这两个渐变将是不同的。
CAGradientLayer
层的startPoint
和endPoint
如何不根据单位坐标空间而是根据标准点坐标来定义,以便渐变的角度/大小不受边界的影响层?
理想的结果是渐变层可以调整为任何大小或形状,并且渐变保持在原位,尽管裁剪不同。
资格:
我知道这似乎是坐标空间之间的一个绝对微不足道的转换,但显然,是的,我实际上就是那么愚蠢,或者CAGradientLayer
s 的工作方式可能存在一些问题或非常违反直觉。我没有提供我期望的正确方法的示例,因为(假设我只是愚蠢)它只会误导。
编辑:
这是我对 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 为您绘制)。
使用蒙版使图层显示为一定的大小和形状,您可以通过更改蒙版来更改该大小和形状,但实际上图层本身就是一个大始终具有相同渐变的恒定大小的图层。
检测到梯度层改变了边界,改变梯度startPoint
和endPoint
匹配。这是一个视图的工作示例,其图层是渐变图层并执行此操作 - 但您必须记住每次边界更改时都重新绘制图层!
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绘制渐变色的方法实例