在 ForEach SwiftUI 中使用 Array 本身以编程方式更改 TabView 的选择

Change selection of TabView programatically using Array itself in ForEach SwiftUI

我有一个 TabView,其中有一个用于其中各种项目的 ForEach 循环,我想使用一个自动更改选择索引的计时器来更改 TabView 项目的选择。我可以使用具有 array.indices0..<array.count 的 ForEach 循环来实现它,但是由于使用前面提到的方法是不安全的,所以我想将数组本身简单地传递到 ForEach 循环中,但是虽然简单在 foreach 循环中使用数组不会使用计时器或其他编程方式更改所选索引。用户需要手动滚动以更改选择。下面是我试过的代码行,谁能指出我做错了什么。

struct ContentView: View {

@State var currentIndex = 0
@State var itemNames = [ItemNames]()
@State var timer: Timer.TimerPublisher = Timer.publish (every: 6, on: .main, in: .common)


var body: some View {
    TabView(selection: $currentIndex) {
        ForEach(itemNames, id: \.id) { item in
            Text(item.name).tag(Int(item.id))
        }
        }.tabViewStyle(.page(indexDisplayMode: .never))
         .onReceive(timer, perform: {
             _ in withAnimation {
                 currentIndex = currentIndex < itemNames.count ? currentIndex + 1 : 0
             }
         }).onDisappear {
             self.cancelTimer()
         }.onAppear {
             setDemoNames()
             self.instantiateTimer()
             _ = self.timer.connect()
         }
    
}

func instantiateTimer() {
                self.timer = Timer.publish (every: 6, on: .main, in: .common)
                return
}

func cancelTimer() {
                self.timer.connect().cancel()
                return
}

func setDemoNames(){
    let item1 = ItemNames(id: "1", name: "John")
    let item2 = ItemNames(id: "2", name: "Mark")
    let item3 = ItemNames(id: "3", name: "Steve")
    let item4 = ItemNames(id: "4", name: "Peter")
    itemNames = [item1, item2, item3, item4]
}
}


struct ItemNames : Identifiable, Hashable {

  var id:String, name:String;
  init(id: String, name: String) {
      self.id = id
      self.name = name
  }
}

类型必须完全匹配

将您的标签更改为

.tag(Int(item.id) as! Int)

以上行有效,因为它删除了 optional/forces.

您必须确保 item.id 始终有效 Int

Int(item.id) 生成类型 Int? 的值,因为它可能会失败

你也可以像下面这样不强制执行,但如果由于某种原因你有 2 个失败的 ID,你可能会有重复的标签。

.tag((Int(item.id) ?? itemNames.count + 1) as Int)

这很容易出现错误,它只在非常特定的情况下有效,而且几乎没有后备方案。

我会将选择变量切换为 String 并将 tag 保留为原始 id 然后创建一个函数来拉下一个 id 以使用定时器。

没有强制或可选。

您还可以通过使用 idInt 而不是 String

来实现此目的