Here is the playground to get the idea
import SwiftUI
import PlaygroundSupport
struct RectangleStyle {
public var color: Color? = nil
public var gradient: LinearGradient? = nil
}
struct DemoView: View {
var body: some View {
Rectangle()
.fill(
RectangleStyle(
gradient: LinearGradient(
gradient: Gradient(colors: [.red, .blue]),
startPoint: .top,
endPoint: .bottom
)
).gradient!
)
.frame(width: 200, height: 200)
}
}
PlaygroundPage.current.setLiveView(DemoView())
As you can see, it's quite ugly. What I would like, is the ability to construct my RectangleStyle
with whatever object that implement ShapeStyle
(the protocol required by the fill()
method on Rectangle
) and be able to retrieve this ShapeStyle
(A Color
or a Gradient
, etc...) with a single method.
If I add a init(style: ShapeStyle)
on my RectangleStyle
, I get the error Protocol "ShapeStyle" can only be used as a generic constraint because it has Self or associated type requirements
.
And I get the same error if I try to add a func getStyle() -> ShapeStyle
on my RectangleStyle
.
How can I properly handle this case? The idea is just to be able to construct my RectangleStyle
with any object of type compatible with the required type of Rectangle.fill()
and have a method to return this object.
Is is possible to let Swift know that if the argument was of type A, the return of a method will be the same type (like in Typescript)?
Thanks!
CodePudding user response:
It can be done with generics, like
struct RectangleStyle<S: ShapeStyle> {
private let style: S
init(_ style: S) { // << your init !!
self.style = style
}
func getStyle() -> some ShapeStyle { // << your func !!
self.style
}
}
and now your test:
let myStyle = RectangleStyle(LinearGradient(
gradient: Gradient(colors: [.red, .blue]),
startPoint: .top,
endPoint: .bottom
))
var body: some View {
Rectangle()
.fill(myStyle.getStyle()) // << here !!
.frame(width: 200, height: 200)
}
Tested with Xcode 13.4 / iOS 15.5