SwiftUI中any Shape无法适配Shape类型的优雅解决方案咨询
SwiftUI中存储不同Shape并统一渲染的问题
我尝试在SwiftUI里根据卡片类型,在卡片上绘制不同形状,写了如下代码:
import SwiftUI let shapes: [any Shape] = [Circle(), Rectangle(), Ellipse()] struct CardView: View { var body: some View { VStack { ForEach(0..<shapes.count) { index in applyStyling(on: shapes[index]) } } } func applyStyling(on shape: some Shape) -> some View { shape.fill(.yellow) } }
但在applyStyling(on: shapes[index])这一行报错:Type 'any Shape' cannot conform to 'Shape'。
我知道用any Shape会丢失底层Shape类型的具体信息,但看到WWDC2022《Embrace Swift generics》视频25:20左右的示例似乎用了类似的写法,所以想不通问题出在哪。
我的需求是:把所有可绘制的形状存在数组里,然后根据传入CardView的形状类型绘制对应的形状。我试过AnyShape方案,但觉得太复杂不够优雅,想找更简洁的实现或者重构方式。
解决方案
方案1:用枚举封装Shape类型
这种方式符合SwiftUI类型安全特性,易维护且逻辑清晰:
import SwiftUI enum ShapeType: CaseIterable { case circle, rectangle, ellipse var shape: some Shape { switch self { case .circle: return Circle() case .rectangle: return Rectangle() case .ellipse: return Ellipse() } } } struct CardView: View { var body: some View { VStack { ForEach(ShapeType.allCases, id: \.self) { shapeType in applyStyling(on: shapeType.shape) } } } func applyStyling(on shape: some Shape) -> some View { shape.fill(.yellow) .frame(width: 100, height: 100) } }
方案2:直接存储带样式的View数组
如果不需要单独存储原始Shape,可以直接把已添加样式的Shape包装成View存入数组:
import SwiftUI let shapeViews: [any View] = [ Circle().fill(.yellow).frame(width: 100, height: 100), Rectangle().fill(.yellow).frame(width: 100, height: 100), Ellipse().fill(.yellow).frame(width: 100, height: 100) ] struct CardView: View { var body: some View { VStack { ForEach(Array(shapeViews.enumerated()), id: \.offset) { _, view in view } } } }
方案3:修正原代码的泛型约束
原问题中applyStyling函数的参数用了some Shape(要求具体的Shape类型),但数组元素是any Shape(类型擦除后的存在类型),两者不兼容。只需将函数参数改为any Shape即可:
import SwiftUI let shapes: [any Shape] = [Circle(), Rectangle(), Ellipse()] struct CardView: View { var body: some View { VStack { ForEach(0..<shapes.count, id: \.self) { index in applyStyling(on: shapes[index]) } } } func applyStyling(on shape: any Shape) -> some View { shape.fill(.yellow) .frame(width: 100, height: 100) } }
注:WWDC示例能运行的原因是,示例中的draw函数参数用的是any Shape,和上述方案3的修正逻辑一致。
内容的提问来源于stack exchange,提问作者Madu
相关产品推荐
相关产品推荐

