首先,我想说的是值更新,因为我在控制台中打印了值,当然,点击每个选项都会按预期打印。但是,出于 UI 目的,我添加了一些视觉组件/样式来帮助指示当前选择。
我的枚举:
enum Gender : Int, CaseIterable {
case men = 0
case women = 1
private var cases: [String] {
["Men", "Women"]
}
func toString() -> String {
cases[self.rawValue]
}
}
这是有助于显示数据和索引数据的逻辑的视图
struct GenderTabMenuIndicator: View {
var category: Gender
var body: some View {
HStack {
ForEach(0..<Gender.allCases.count) { cat in
GenderTabMenuIndicatorItem(category: Gender.allCases[cat], isActive: Gender.allCases[cat] == category)
}
}.frame(width: UIScreen.main.bounds.width * 0.75)
}
}
这只是观点。然而,
isActive
似乎没有从初始选择/值切换。
struct GenderTabMenuIndicatorItem: View {
@State var category: Gender
@State var isActive: Bool
var body: some View {
VStack(spacing: 0) {
Text(category.toString().uppercased())
.onTapGesture {
print("tapped")
print(category.toString())
}
.font(.system(size: 18, weight: isActive ? .bold : .light))
.frame(maxWidth: .infinity)
.layoutPriority(1)
if isActive {
Rectangle()
.frame(width: 50, height: 2, alignment: .center)
}
}.foregroundColor(Color(SYSTEM_FONT_COLOUR))
}
}
这就是我在实际视图中声明/使用所有这些组件的方式:
@State private var selected_tab: Gender = .men
VStack {
GenderTabMenuIndicator(category: selected_tab)
}
我不知道这是否是ForEach循环,但同时确实打印了传递的相应案例。我已经在可以的地方使用了 @State 来更新视图,但没有成功。
如有任何帮助,我们将不胜感激!
@State
用于在视图内进行私有更改
要从子视图来回更新更改,您必须使用@Binding
@State
访问/传递
$
的绑定,ex :-
$yourStateVariable
// If you change the type of this `enum` to `String`, you can use
// `.rawValue.capitalized` instead of manually mapping all cases
// to create a `toString` method/computed property. But assuming
// you absolutely need to have `Int` as the `RawValue` type, you
// should instead utilize a switch statement because it gives you
// compile-time checking/safety if the order of these values ever
// changes or if new cases are ever added, as I have done here.
enum Gender : Int, CaseIterable {
case men = 0
case women = 1
func toString() -> String {
switch self {
case .men: "Men"
case .women: "Women"
}
}
}
struct ContentView: View {
@State private var selectedGender: Gender = .men
var body: some View {
VStack {
Text("Selected: \(selectedGender.toString())")
GenderTabMenuIndicator(
selectedGender: $selectedGender
)
}
}
}
// If you were to change the `Gender` `enum` `RawValue` type to `String`,
// you could then make this view type reusable by making it take a generic type
// and then it would work for any `enum` with a `String` as its `RawValue` type.
struct GenderTabMenuIndicator: View {
@Binding var selectedGender: Gender
var body: some View {
HStack {
ForEach(Gender.allCases) { gender in
GenderTabMenuIndicatorItem(
gender: gender,
selection: $selectedGender
)
}
} // NOTE: Apple advises not to use UIScreen for SwiftUI
.frame(width: UIScreen.main.bounds.width * 0.75)
}
}
// Same here:
// If you were to change the `Gender` `enum` `RawValue` type to `String`,
// you could then make this view type reusable by making it take a generic type
// and then it would work for any `enum` with a `String` as its `RawValue` type.
struct GenderTabMenuIndicatorItem: View {
var category: Gender
@Binding var selection: Gender
var isSelected: Bool { selection == gender }
var body: some View {
VStack(spacing: 0) {
Text(gender.toString().uppercased())
.onTapGesture {
selection = category
}
.font(.system(
size: 18,
weight: isSelected ? .bold : .light
))
.frame(maxWidth: .infinity)
.layoutPriority(1)
if isSelected {
Rectangle()
.frame(width: 50, height: 2, alignment: .center)
}
}
}
}
enum Gender: String, CaseIterable {
case man
case woman
}
enum MaritalStatus: String, CaseIterable {
case single
case married
case separated
case divorced
}
struct ContentView: View {
@State private var gender = Gender.man
@State private var maritalStatus = MaritalStatus.single
var body: some View {
VStack {
Text("Gender: \(gender.rawValue.capitalized)")
TabMenuIndicator(selectedItem: $gender)
Text("Marital Status: \(maritalStatus.rawValue.capitalized)")
TabMenuIndicator(selectedItem: $maritalStatus)
}
}
}
struct TabMenuIndicator<ItemType: RawRepresentable, CaseIterable, Equatable>: View {
@Binding var selectedItem: ItemType
var body: some View {
HStack {
ForEach(ItemType.allCases) { anItem in
TabMenuItem(
item: anItem,
selectedItem: $selectedItem
)
}
} // NOTE: Apple advises not to use UIScreen for SwiftUI
.frame(width: UIScreen.main.bounds.width * 0.75)
}
}
struct TabMenuItem<ItemType: RawRepresentable, CaseIterable, Equatable>: View {
var item: ItemType
@Binding var selectedItem: ItemType
var isSelected: Bool { selectedItem == item }
var body: some View {
VStack(spacing: 0) {
Text(item.rawValue.capitalized)
.onTapGesture {
selectedItem = item
}
.font(.system(
size: 18,
weight: isSelected ? .bold : .light
))
.frame(maxWidth: .infinity)
.layoutPriority(1)
if isSelected {
Rectangle()
.frame(width: 50, height: 2, alignment: .center)
}
}
}
}