Swift 5.x iOS 13.x
我创建了一个骰子视图数组,我想在它们之间切换。为了简短起见,我仅在此处显示两个视图。我创建了一个视图数组,但是我还不太清楚如何在SwiftUI中解决它?或视图实际上是什么样的对象,因为它不是视图,也不是某种视图。
import SwiftUI
import GameplayKit
let dotSize:CGFloat = 24
let diceSize:CGFloat = 128
let fieldSide:CGFloat = 32
let d6 = GKRandomDistribution.d2()
var diceViews:[Any] = [oneDotDice(),twoDotDice()]
struct ContentView: View {
@State var showInt:Int = 1
var body: some View {
VStack {
if showInt == 1 {
oneDotDice()
.transition(AnyTransition.opacity)
.animation(.default)
.modifier(changeDice(showInt: self.$showInt))
}
if showInt == 2 {
twoDotDice()
.transition(AnyTransition.opacity)
.animation(.default)
.modifier(changeDice(showInt: self.$showInt))
}
}
}
struct oneDotDice: View {
var body: some View {
Rectangle()
.fill(Color.clear)
.frame(width: diceSize, height: diceSize, alignment: .center)
.border(Color.black)
.background(Text(1))
}
}
struct twoDotDice: View {
var body: some View {
Rectangle()
.fill(Color.clear)
.frame(width: diceSize, height: diceSize, alignment: .center)
.border(Color.black)
.background(Text(2))
}
}
struct changeDice: ViewModifier {
@Binding var showInt:Int
func body(content: Content) -> some View {
content
.onTapGesture {
self.showInt = d6.nextInt()
print("Int ",self.showInt)
}
}
}
如何在主循环中使用我的视图数组使此代码更好?我什至不能在SwiftUI代码中使用switch语句。我需要使用六个嵌套的if / else语句...
答案 0 :(得分:4)
视图只是一个结构。您可以将其存储在数组或其他属性类型中,然后在其他视图中使用。如果您确实想在一个集合中混合使用不同类型的View,那么AnyView
是一个很好的解决方案。
为了动态显示该集合,我喜欢使用ForeEach。您可以不迭代确切的View,而可以迭代数组的索引。因此,SwiftUI将根据其视图的数组索引为其创建键。但这是有代价的。您不能动态更改该数组的内容。在所有父级View生命周期中,它必须恒定。
坦白地说,您实际上可以通过ForeEach迭代确切的View,但是需要使它们可识别(它们必须具有public var id = UUID()
属性)。
import SwiftUI
let dotSize:CGFloat = 24
let diceSize:CGFloat = 128
let fieldSide:CGFloat = 32
struct ContentView: View {
var diceViews:[AnyView] = [AnyView(oneDotDice()), AnyView(twoDotDice())]
@State var showInt: Int = 1
var body: some View {
ZStack{
ForEach(diceViews.indices){ind in
ZStack{
if ind == self.showInt{
self.diceViews[ind]
.transition(.scale(scale: 0, anchor: .center))
.onTapGesture {
let newShow = Int.random(in: 0...1)
print("new show id \(newShow)")
withAnimation(.linear(duration: 0.3)){
self.showInt = newShow
}
}
}
}
}
}
}
}
struct oneDotDice: View {
var text: String = "1"
var body: some View {
Rectangle()
.fill(Color.clear)
.frame(width: diceSize, height: diceSize)
.border(Color.black)
.background(Text(text))
}
}
struct twoDotDice: View {
var text: String = "2"
var body: some View {
Rectangle()
.fill(Color.clear)
.frame(width: diceSize, height: diceSize)
.border(Color.black)
.background(Text(text))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
顺便说一句,我改变了您的随机逻辑,不确定它是如何工作的,但是我认为它对您的问题并不是很重要。
答案 1 :(得分:1)
我建议您删除oneDotDice
和twoDotDice
,以拥有一个可以代表所有可能值的DiceFace
。另外,不需要自定义修饰符,不需要View
数组(顺便说一句,如果您想要类似的内容,可以使用AnyView
或ForEach
)。
您可以将以下示例复制粘贴到Playground中进行检查:
import SwiftUI
import GameplayKit
import PlaygroundSupport
let dotSize: CGFloat = 24
let diceSize: CGFloat = 128
let fieldSide: CGFloat = 32
let d6 = GKRandomDistribution(forDieWithSideCount: 6)
struct ContentView: View {
@State var currentValue: Int = 1
var body: some View {
DiceFace(dotCount: currentValue)
.transition(AnyTransition.opacity)
.animation(.default)
.onTapGesture(perform: self.roll)
}
func roll() {
self.currentValue = d6.nextInt()
print("Int: \(self.currentValue)")
}
// Your `oneDotDice` and `twoDotDice` can be represented with this View, passing simply a different `dotCount`
// Also, in Swift types go with an uppercase, and variables with a lowercase.
struct DiceFace: View {
let dotCount: Int
var body: some View {
Rectangle()
.fill(Color.clear)
.frame(width: diceSize, height: diceSize, alignment: .center)
.border(Color.black)
.background(Text(String(dotCount)))
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
PlaygroundPage.current.needsIndefiniteExecution = true