Open jjatie opened 6 years ago
@larryonoff @liuxuan30
The similar class can be introduced for radial gradient like func drawRadialGradient(CGGradient, startCenter: CGPoint, startRadius: CGFloat, endCenter: CGPoint, endRadius: CGFloat, options: CGGradientDrawingOptions)
final class RadialGradient: NSObject, NSCopying
{
let startCenter: CGPoint
let startRadius: CGFloat
let endCenter: CGPoint
let endRadius: CGFloat
let positions: [CGFloat]
let colors: [UIColor]
}
I think it may be useful adding one more parameter, i.e. let options: CGGradientDrawingOptions
Seems reasonable. I feel like there should be a default value for this parameter as well in the initializer. I'm thinking []
One more protocol can be introduced for extensibility
protocol GradientRenderer {
func draw(_ gradient: CGGradient, in context: CGContext)
}
so that RadialGradient
and LinearGradient
conform it.
Please target the 4.0.0 branch for this PR.
I think the naming should be different if the Gradient
's themselves are conforming to it. Either Drawable
and implement it's own draw(in context: CGContext)
or, what I think makes more sense, the Renderer
is a separate type altogether.
@jjatie Is there any place that these types can be used ?
I've definitely looked at a lot of gradient work, but I can't remember what's merged and what's not. At work right now, so I'll have to check later.
Regardless I think this is a welcome addition, and we should have more things like it.
I like draw(in context: CGContext)
but it looks that CGGradient should be an input parameter for protocol since of signatures of these two methods below.
func drawLinearGradient(CGGradient, start: CGPoint, end: CGPoint, options: CGGradientDrawingOptions)
func drawRadialGradient(CGGradient, startCenter: CGPoint, startRadius: CGFloat, endCenter: CGPoint, endRadius: CGFloat, options: CGGradientDrawingOptions)
This is where a separate Renderer
type comes in. If we have
protocol Drawable {
func draw(in context: CGContext)
}
struct RadialGradient: Drawable {
// properties
func draw(in context: CGContext) {
}
}
It doesn't make sense for the gradient to pass itself into it's own method.
It does make sense though to have
protocol GradientRenderer: Renderer {
func draw(_ gradient: Gradient, in context: CGContext)
}
and attach the protocol on the appropriate renders.
The more I think about this, the more I wonder if we shouldn't abstract this more i.e.
protocol Drawable {
func draw(in context: CGContext)
}
protocol Renderer {
func render(_ drawable: Drawable, in context: CGContext)
}
extension Renderer {
func draw(_ drawable: Drawable, in context: CGContext) {
drawable.draw(in: context)
}
}
I created some basic PR #3429. That of course needs improvements / discussions / changes.
The alternative is to rely solely on CGGradient
. I think internally we should only rely on it, but the consumer should get a nicer API to work with. A question I have is, how are positions defined in our Gradient
type? InCGGradient
, they represent a fraction of the total drawn gradient, and the locations on screen are accepted by CGContext.drawLinearGradient
method.
I see the following options for locations:
CGGradient
from 0
to 1
.I think that option 2 is better since it's easier to define gradient transition locations relative to axis values.
We may introduce the following enum to cover both options 1 and 2.
enum GradientLocationsStrategy {
case relative
case normalised
}
PS. I don't like using CGGradient in protocol. But I don't see better way to calculate locations yet.
@jjatie Hi! I've replied you in Gitter.
Motivation
There are many feature requests involving gradients, in addition to the currently existing gradient related features. PRs have been submitted with multiple implementations and concepts as to how to describe a gradient. In an effort to standardize our gradient support, we would like to introduce a new
Gradient
data type.credit: @larryonoff
Impletmentation
In a pure Swift implementation, this would be:
However, as we are still currently supporting objc, this is required:
To simplify creation of gradients, we should introduce convenience initializers for standard gradient positions and default colour options.
It may make sense to introduce additional gradient types (radial, etc), however further discussion should be had as to whether it is necessary. If we are going to do so, we should do it the Swift way, by defining a
Gradient
protocol instead of subclassing to make the eventual transition away from objective-c easier.