如何对各种形状使用同一组修饰符
How to use same set of modifiers for various shapes
作为我学习 SwiftUI 项目的一部分,我做了一些形状旋转,下面有代码。我想知道如何避免为每个形状使用相同的三行修饰符。
func getShape(shape: Int, i: Int) -> AnyView {
switch shape {
case 0:
return AnyView(Rectangle()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
case 1:
return AnyView(Capsule()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
case 2:
return AnyView(Ellipse()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
default:
return AnyView(Rectangle()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
}
}
您可以通过使用辅助函数和扩展来抽象一些重复。
在下面的简化示例中,我使用 @ViewBuilder
来清理我们正在 returning 的代码。无需使用 AnyView
,它使代码更易于阅读。
如果可以的话就太好了returnsome Shape
然而这是
目前不可能并导致错误。这就是为什么中风
必须为 getShape
中的每个 Shape
重复值
功能,否则我们可以在 Shape
上进行扩展
而不是 View
.
我在 View
上创建了一个扩展,允许我们将修饰符组合到一个函数中,使其更具可读性和易用性。老实说,这部分是可选的,您可以使用两个修饰符 frame
和 rotationEffect
.
@ViewBuilder getShape(shape:index:)
returns 是您选择的带有所选颜色的形状,然后由函数 createShape(shape:index:)
使用,您可以在其中添加自定义我们在 View
.
上作为扩展创建的修饰符
最后我们创建了我们的形状
这应该给你一个起点。
struct ShapeView: View {
@ViewBuilder // 1
func getShape(shape: Int, i: Int) -> some View {
switch shape {
case 0:
Rectangle().stroke(Color.red)
case 1:
Capsule().stroke(Color.red)
case 2:
Ellipse().stroke(Color.red)
default:
Rectangle().stroke(Color.red)
}
}
func createShape(shape: Int, index: Int) -> some View { // 3
getShape(shape: shape, i: index)
.myModifier(width: 200, height: 100, index: index, angleStep: 30)
}
var body: some View {
createShape(shape: 2, index: 1) // 4
}
}
// 2
extension View {
func myModifier(width: CGFloat, height: CGFloat, index: Int, angleStep: Double) -> some View {
self
.frame(width: width, height: height)
.rotationEffect(Angle(degrees: Double(index) * Double(angleStep)))
}
}
struct ShapeView_Previews: PreviewProvider {
static var previews: some View {
ShapeView()
}
}
很遗憾我们不能从 @ViewBuilder
return some Shape
或者如果存在 @ShapeBuilder
因为这意味着我们不会有将笔画单独添加到每个形状,因为 View
不能有笔画。
使用助手 AnyShape
键入橡皮擦
struct AnyShape: Shape {
private let builder: (CGRect) -> Path
init<S: Shape>(_ shape: S) {
builder = { rect in
let path = shape.path(in: rect)
return path
}
}
func path(in rect: CGRect) -> Path {
return builder(rect)
}
}
你的函数可以写成
func getShape(shape: Int, i: Int) -> some View {
let selectedShape: AnyShape = {
switch shape {
case 0:
return AnyShape(Rectangle())
case 1:
return AnyShape(Capsule())
case 2:
return AnyShape(Ellipse())
default:
return AnyShape(Rectangle())
}
}()
return selectedShape
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
}
嵌套函数可以帮助清理代码:
func getShape(shape: Int, i: Int) -> some View {
func adjustedView<S: Shape>(shape: S) -> some View {
shape
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
}
return Group {
switch shape {
case 0:
adjustedView(shape: Rectangle())
case 1:
adjustedView(shape: Capsule())
case 2:
adjustedView(shape: Ellipse())
default:
adjustedView(shape: Rectangle())
}
}
}
另一种选择是使用便利功能扩展 Shape
。即
extension Shape {
func adjust(shapeWidth: Double, shapeHeight: Double, angle: Angle) -> some View {
self.stroke()
//.stroke(colors[Int(shapeColor)]) // for brevity
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(angle)
}
}
它简化了代码。也不需要擦除类型。
func getShape(shape: Int, i: Int) -> some View {
Group {
switch shape {
case 0:
Rectangle().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
case 1:
Capsule().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
case 2:
Ellipse().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
default:
Rectangle().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
}
}
}
作为我学习 SwiftUI 项目的一部分,我做了一些形状旋转,下面有代码。我想知道如何避免为每个形状使用相同的三行修饰符。
func getShape(shape: Int, i: Int) -> AnyView {
switch shape {
case 0:
return AnyView(Rectangle()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
case 1:
return AnyView(Capsule()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
case 2:
return AnyView(Ellipse()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
default:
return AnyView(Rectangle()
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
}
}
您可以通过使用辅助函数和扩展来抽象一些重复。
在下面的简化示例中,我使用
@ViewBuilder
来清理我们正在 returning 的代码。无需使用AnyView
,它使代码更易于阅读。如果可以的话就太好了return
some Shape
然而这是 目前不可能并导致错误。这就是为什么中风 必须为getShape
中的每个Shape
重复值 功能,否则我们可以在Shape
上进行扩展 而不是View
.我在
View
上创建了一个扩展,允许我们将修饰符组合到一个函数中,使其更具可读性和易用性。老实说,这部分是可选的,您可以使用两个修饰符frame
和rotationEffect
.
上作为扩展创建的修饰符@ViewBuilder getShape(shape:index:)
returns 是您选择的带有所选颜色的形状,然后由函数createShape(shape:index:)
使用,您可以在其中添加自定义我们在View
.最后我们创建了我们的形状
这应该给你一个起点。
struct ShapeView: View {
@ViewBuilder // 1
func getShape(shape: Int, i: Int) -> some View {
switch shape {
case 0:
Rectangle().stroke(Color.red)
case 1:
Capsule().stroke(Color.red)
case 2:
Ellipse().stroke(Color.red)
default:
Rectangle().stroke(Color.red)
}
}
func createShape(shape: Int, index: Int) -> some View { // 3
getShape(shape: shape, i: index)
.myModifier(width: 200, height: 100, index: index, angleStep: 30)
}
var body: some View {
createShape(shape: 2, index: 1) // 4
}
}
// 2
extension View {
func myModifier(width: CGFloat, height: CGFloat, index: Int, angleStep: Double) -> some View {
self
.frame(width: width, height: height)
.rotationEffect(Angle(degrees: Double(index) * Double(angleStep)))
}
}
struct ShapeView_Previews: PreviewProvider {
static var previews: some View {
ShapeView()
}
}
很遗憾我们不能从 @ViewBuilder
return some Shape
或者如果存在 @ShapeBuilder
因为这意味着我们不会有将笔画单独添加到每个形状,因为 View
不能有笔画。
使用助手 AnyShape
键入橡皮擦
struct AnyShape: Shape {
private let builder: (CGRect) -> Path
init<S: Shape>(_ shape: S) {
builder = { rect in
let path = shape.path(in: rect)
return path
}
}
func path(in rect: CGRect) -> Path {
return builder(rect)
}
}
你的函数可以写成
func getShape(shape: Int, i: Int) -> some View {
let selectedShape: AnyShape = {
switch shape {
case 0:
return AnyShape(Rectangle())
case 1:
return AnyShape(Capsule())
case 2:
return AnyShape(Ellipse())
default:
return AnyShape(Rectangle())
}
}()
return selectedShape
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
}
嵌套函数可以帮助清理代码:
func getShape(shape: Int, i: Int) -> some View {
func adjustedView<S: Shape>(shape: S) -> some View {
shape
.stroke(colors[Int(shapeColor)])
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(Angle(degrees: Double(i) * Double(angleStep))))
}
return Group {
switch shape {
case 0:
adjustedView(shape: Rectangle())
case 1:
adjustedView(shape: Capsule())
case 2:
adjustedView(shape: Ellipse())
default:
adjustedView(shape: Rectangle())
}
}
}
另一种选择是使用便利功能扩展 Shape
。即
extension Shape {
func adjust(shapeWidth: Double, shapeHeight: Double, angle: Angle) -> some View {
self.stroke()
//.stroke(colors[Int(shapeColor)]) // for brevity
.frame(width: CGFloat(shapeWidth), height: CGFloat(shapeHeight))
.rotationEffect(angle)
}
}
它简化了代码。也不需要擦除类型。
func getShape(shape: Int, i: Int) -> some View {
Group {
switch shape {
case 0:
Rectangle().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
case 1:
Capsule().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
case 2:
Ellipse().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
default:
Rectangle().adjust(shapeWidth: shapeWidth, shapeHeight: shapeHeight, angle: Angle(degrees: Double(i) * Double(angleStep))))
}
}
}