在循环中生成视图时,绑定在视图中不起作用

时间:2019-11-16 17:24:20

标签: binding swiftui

问题: 我试图通过不使用12次相同的MonthView()而是循环使用来使本示例https://swiftui-lab.com/communicating-with-the-view-tree-part-1/更快一些。 不幸的是,当点击标签/月时,变量activeIdx不会被更新,我也不知道为什么... 我的问题是:我该如何更改绑定有效的代码? 预期的行为: 当您点击月份名称时,红色边框应标记您所点击的标签。

import SwiftUI

let months : [String] = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]

struct ContentView : View {

    @State private var activeIdx: Int = 0

    var groupedGroupedViews : [[MonthView]] = []

    init() {

        var groupedViews : [MonthView] = []
        for idx in 0..<months.count {
            print(idx)
            groupedViews.append(MonthView(activeMonth: self.$activeIdx, label: months[idx], idx: idx))
            print(months[idx])
            if (idx + 1) % 4 == 0 {
                groupedGroupedViews.append(groupedViews)
                groupedViews = []
            }
        }
        groupedGroupedViews.append(groupedViews)
    }

    var body: some View {
        VStack {
            ForEach (groupedGroupedViews, id: \.self) { groupedViews in
                HStack {
                    ForEach (groupedViews, id: \.idx) { view in
                        view
                    }
                }
            }
        }
    }
}

struct MonthView: View, Hashable {

    func hash(into hasher: inout Hasher) {
        hasher.combine(idx)
    }

    static func == (lhs: MonthView, rhs: MonthView) -> Bool {
        return lhs.idx == rhs.idx
    }

    @Binding var activeMonth: Int
    let label: String
    var idx: Int

    var body: some View {
        Text(label)
            .padding(10)
            .onTapGesture {
                print(self.idx, " tapped")
                self.activeMonth = self.idx
                print("active = ", self.activeMonth)
        }

            .background(MonthBorder(show: activeMonth == idx))
    }
}

struct MonthBorder: View {
    let show: Bool

    var body: some View {
        RoundedRectangle(cornerRadius: 15)
            .stroke(lineWidth: 3.0).foregroundColor(show ? Color.red : Color.clear)
            .animation(.easeInOut(duration: 0.6))
    }
}

2 个答案:

答案 0 :(得分:1)

原因是您不能init这样的绑定视图。

var myView : MonthView!
init() {
  myView =  MonthView(activeMonth: self.$activeIdx, label: months[0], idx: 1)
} 

var body: some View {
    myView}

如果运行上面的代码,您仍然可以看到activeMonth没有变化。

我认为init()主要是一些UIKit功能的桥梁,不应作为SwiftUI的主要方式。跨平台是必要的,但请尽量避免。请欣赏swiftUI的设计优点,而不是传统实现的开销。

一个简单的答案是将init移至View。达到您所需的相同功能。

 var body: some View {

            let groupedGroupedViews : [[MonthView]] = {
                var groupedGroupedViews : [[MonthView]]  = []
                    var groupedViews : [MonthView] = []
                    for idx in 0..<months.count {
                        print(idx)
                        groupedViews.append( MonthView(activeMonth: self.$activeIdx, label: months[idx], idx: idx))
                        print(months[idx])
                        if (idx + 1) % 4 == 0 {
                            groupedGroupedViews += [groupedViews]
                            groupedViews.removeAll()
                        }
                    }
                    groupedGroupedViews +=  [groupedViews]
                return groupedGroupedViews
            }()

         return   VStack {

                ForEach (groupedGroupedViews, id: \.self) { groupedView in
                    HStack {
                        ForEach (groupedView, id: \.idx) { view in
                        view
                        }
                    }
                }
            }
        }

答案 1 :(得分:0)

我发现了它,多亏了E.Coms,我已经更改了代码,现在它可以工作了。 这是我的解决方案(但我很确定您可以做得更好)

struct ViewValue : Hashable {

    var idx: Int
    var text: String
}


struct ContentView : View {

    @State private var activeIdx: Int = 0

    var groupedGroupedValues : [[ViewValue]] = []

    init() {

        var groupedValues : [ViewValue] = []
        for idx in 0..<months.count {
            print(idx)
            groupedValues.append(ViewValue(idx: idx, text: months[idx]))
            print(months[idx])
            if (idx + 1) % 4 == 0 {
                groupedGroupedValues.append(groupedValues)
                groupedValues = []
            }
        }
        groupedGroupedValues.append(groupedValues)
    }

    var body: some View {
        VStack {
            ForEach (groupedGroupedValues, id: \.self) { groupedValue in
                HStack {
                    ForEach (groupedValue, id: \.idx) { viewValue in
                        MonthView(activeMonth: self.$activeIdx, label: viewValue.text, idx: viewValue.idx)
                    }
                }
            }
        }
    }
}