@State var未按预期更新视图

时间:2020-09-23 11:33:29

标签: swiftui

我在下面的视图中实例化了一行按钮,我打算使它们成为可选择的(一次仅一个)。

//@State var currentSelectedIndex = 0
//var rooms: [Room]
    
        ScrollView(.horizontal, showsIndicators: false, content: {
            HStack {
                ForEach(rooms.indices) { roomIndex in
                    Button(action: {
                        currentSelectedIndex = roomIndex
                    }) {
                        UserSelectionIcon(room: rooms[roomIndex], selected: roomIndex == currentSelectedIndex)
                            .padding(10)
                    }
                }
            }
        })

选择一个时,它周围应显示一个蓝色圆圈。这是我上面引用的UserSelectionIcon对象中的行应执行的操作;

//@State var selected: Bool = false

Circle()
     .strokeBorder(selected ? Color.blue.opacity(0.7) : Color.clear, lineWidth: 2)

此行确实有效,因为选择了第一个索引并显示蓝色圆圈。但是,单击任何按钮都不会显示它们周围的蓝色圆圈。 currentSelectedIndex变量正在按预期进行更新。

1 个答案:

答案 0 :(得分:1)

UserSelectionIcon中,您必须使用Bindings来访问currentSelectedIndex而不是States,因为如果更改值,States不会更新在另一个视图中。

因此,您必须在Bool视图中安全地将Binding“选择”为UserSelectionIcon。更改此:

@State var selected: Bool = false

对此:

@Binding var selected: Bool

并不仅仅是重构此调用:

UserSelectionIcon(room: rooms[roomIndex], selected: roomIndex == currentSelectedIndex)

对此:

UserSelectionIcon(room: rooms[roomIndex], selected: Binding(get: { roomIndex == currentSelectedIndex }, set: {_,_ in }))

现在,您将两个索引的比较包装到一个绑定中,该绑定将始终代表两个索引的最新比较。如果只传递比较,则它就像一个一次性值,如果其中一个索引被更新,它将不会刷新它的结果。但是现在,当您选择应为笔触边框选择哪种颜色时,每次访问绑定时都会重新评估比较。

替代解决方案:

您应该重构它:

UserSelectionIcon(room: rooms[roomIndex], selected: roomIndex == currentSelectedIndex)

对此(传递State变量):

UserSelectionIcon(room: rooms[roomIndex], currentSelectedIndex: currentSelectedIndex)

,在您的UserSelectionIcon中,您应该重构此行:

@State var selected: Bool = false

收件人:

 @Binding var currentSelectedIndex: Bool

,每个图标应保存其索引本身,以便以后进行比较:

var roomIndex: Int

然后您可以在显示边框时比较这两个索引。

.strokeBorder(currentSelectedIndex == roomIndex ? Color.blue.opacity(0.7) : Color.clear, lineWidth: 2)