SwiftUI - 使用枚举查看未更新

问题描述 投票:0回答:1

首先,我想说的是值更新,因为我在控制台中打印了值,当然,点击每个选项都会按预期打印。但是,出于 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 来更新视图,但没有成功。

如有任何帮助,我们将不胜感激!

swift enums swiftui
1个回答
3
投票
  • @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) } } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.