SwiftUI中如何程序化生成视图序列?代码报错解决方案
要生成类似6x4 Macbeth靶标的视图集合,原本需要重复编写带onTapGesture、frame、border修饰符的Color视图,示例代码如下:
VStack(spacing: pad/2) { getRgbColor(i:0) .onTapGesture { editColor(i:0) } .frame(width: pad, height: pad) .border(.black.opacity(0.5), width: 1) getRgbColor(i:1) .onTapGesture { editColor(i:1) } .frame(width: pad, height: pad) .border(.black.opacity(0.5), width: 1) getRgbColor(i:2) .onTapGesture { editColor(i:2) } .frame(width: pad, height: pad) .border(.black.opacity(0.5), width: 1) }
为减少重复代码,尝试将修饰符整合到返回SwiftUI.Color的函数中,代码如下:
func getRgbColor(i:Int) -> SwiftUI.Color { return SwiftUI.Color(red: R + rgbDel[i][0] * step, green: G + rgbDel[i][1] * step, blue: B + rgbDel[i][2] * step) .onTapGesture { editColor(i:0) } .frame(width: pad, height: pad) .border(.black.opacity(0.5), width: 1) as! Color }
这段代码编译可通过,但运行时触发SIGABRT错误,报错信息如下:
Could not cast value of type 'SwiftUI.ModifiedContent<SwiftUI.ModifiedContent<SwiftUI.ModifiedContent<SwiftUI.Color, SwiftUI.AddGestureModifier<SwiftUI._EndedGesture<SwiftUI.TapGesture>>>, SwiftUI._FrameLayout>, SwiftUI._OverlayModifier<SwiftUI._ShapeView<SwiftUI._StrokedShape<SwiftUI.Rectangle._Inset>, SwiftUI.Color>>>' (0x109735e90) to 'SwiftUI.Color' (0x1ec3b9eb8).
2022-10-01 12:38:49.468445+0100 ByEye[2810:493288] Could not cast value of type 'SwiftUI.ModifiedContent<SwiftUI.ModifiedContent<SwiftUI.ModifiedContent<SwiftUI.Color, SwiftUI.AddGestureModifier<SwiftUI._EndedGesture<SwiftUI.TapGesture>>>, SwiftUI._FrameLayout>, SwiftUI._OverlayModifier<SwiftUI._ShapeView<SwiftUI._StrokedShape<SwiftUI.Rectangle._Inset>, SwiftUI.Color>>>' (0x109735e90) to 'SwiftUI.Color' (0x1ec3b9eb8).
错误原因
在SwiftUI中,给Color添加onTapGesture、frame这类修饰符后,返回的不再是单纯的Color类型,而是被ModifiedContent包装的复合视图类型。强行用as! Color进行类型转换必然失败,因为两种类型完全不兼容。
正确解决方案
将函数的返回类型改为some View,即可正确返回带有所有修饰符的完整视图。修改后的代码如下:
func rgbButton(i:Int) -> some View { return SwiftUI.Color(red: R + rgbDel[i][0] * step, green: G + rgbDel[i][1] * step, blue: B + rgbDel[i][2] * step) .onTapGesture { editColor(i:i) } .frame(width: pad, height: pad) .border(.black.opacity(0.5), width: 1) // 可根据需求保留border修饰符 }
之后在VStack中直接调用rgbButton(i:)即可生成所有需要的视图,彻底消除重复代码。
内容的提问来源于stack exchange,提问作者Richard Kirk

