Rya*_*ner 5 swift swiftui swift5.2
使用 Swift 5.2 我想创建一个函数来动态更改形状
我有一个像
import SwiftUI
struct CardView: View {
let suit : Suite
let rank : Rank
var body: some View {
getShape(suite: .heart)
.fill(Color.red) // .fill(suit.color)
.frame(width: 100, height: 100)
}
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个协议返回类型为 Shape 的函数,我在下面的示例中将自定义形状替换为通用
func getShape(suite:Suite) -> Shape {
switch suite {
case .heart:
return Circle() // Heart()
case .diamond:
return Rectangle() // Diamond()
case .spade:
return Circle() // Heart()
case .club:
return Circle() // Club()
}
}
Run Code Online (Sandbox Code Playgroud)
我不能对某些不透明类型使用不透明类型,因为我返回不同的类型并且出现编译错误
Function declares an opaque return type, but the return statements in its body do not have matching underlying types
Run Code Online (Sandbox Code Playgroud)
我也不能保持协议类型不变,因为我收到错误
Protocol 'Shape' can only be used as a generic constraint because it has Self or associated type requirements
Run Code Online (Sandbox Code Playgroud)
有什么办法可以优雅地实现这一目标吗?
通过将@Asperi 的回答与
struct AnyShape: Shape {
init<S: Shape>(_ wrapped: S) {
_path = { rect in
let path = wrapped.path(in: rect)
return path
}
}
func path(in rect: CGRect) -> Path {
return _path(rect)
}
private let _path: (CGRect) -> Path
}
Run Code Online (Sandbox Code Playgroud)
我可以把它改成
func getShape(suite:Suite) -> some Shape {
switch suite {
case .club:
return AnyShape(Club())
case .diamond:
return AnyShape(Diamond())
case .heart:
return AnyShape(Heart())
case .spade:
return AnyShape(Spade())
}
}
struct CardView: View {
let suit : Suite
let rank : Rank
var body: some View {
getShape(suite: suit)
.fill(Color.red)
.frame(width: 100, height: 100)
}
Run Code Online (Sandbox Code Playgroud)
这是可能的解决方案。使用 Xcode 11.4 测试。
struct CardView: View {
let suit : Suite
let rank : Rank
var body: some View {
// pass all dependencies to generate view
getShape(suite: .heart, fill: suit.color)
.frame(width: 100, height: 100)
}
}
// Generate complete view and return opaque type
func getShape(suite: Suite, fill color: Color) -> some View {
switch suite {
case .heart:
return AnyView(Heart().fill(color))
case .diamond:
return AnyView(Diamond().fill(color))
case .spade:
return AnyView(Spade().fill(color))
case .club:
return AnyView(Club().fill(color))
}
}
Run Code Online (Sandbox Code Playgroud)
只是想把这个留在这里:
https://github.com/ohitsdaniel/ShapeBuilder
我最近开源了一个 ShapeBuilder,它允许通过利用结果构建器将计算属性和函数标记为@ShapeBuilder或@InsettableShapeBuilder避免类型擦除。
这将允许您编写以下代码:
import ShapeBuilder
@ShapeBuilder func getShape(suite:Suite) -> some Shape {
switch suite {
case .heart:
Heart()
case .diamond:
Diamond()
case .spade:
Heart()
case .club:
Club()
}
}
Run Code Online (Sandbox Code Playgroud)
我还建议不要擦除 AnyView,如前面的答案所述。相反,标记您可以使用 @ViewBuilder 标记您的 getShape 函数。这会将函数体变成视图构建器,就像 SwiftUI View body 属性一样,并避免类型擦除,从而使 SwiftUI 能够更轻松地维护结构视图标识。
| 归档时间: |
|
| 查看次数: |
1035 次 |
| 最近记录: |