SwiftUI在枚举变量更改时更新CustomView

时间:2020-02-20 17:12:11

标签: swiftui

我在3x4网格上有几个月的浏览量。每个子视图都是一个小框,其中包含选中/未选中的月份名称和状态。问题是...我想从父视图中观察枚举变量,并取消选择除最后一次按下以外的所有按钮。

到目前为止,我已经实现了下一个逻辑。最初,我有 currentMonthSelected ,状态为.none (未选择月份)。当我按下 JAN 按钮时,我将 currentMonthSelected == .jax传递给单月子视图,它返回给我返回更改currentMonthSelected应该遵守的回调其他视图。

ParentView

@State var currentMonthSelected: MonthsTypes = .none

SingleButtonView(title: .jan, isSelected: currentMonthSelected == .jan ? true : false, action: { month in
   self.currentMonthSelected = month
})

SingleButtonView(title: .feb, isSelected: currentMonthSelected == .feb ? true : false, action: { month in
   self.currentMonthSelected = month
})

单月子视图

struct SingleButtonView: View {
var title: MonthsTypes = .none
@State var isSelected = false
var action: (MonthsTypes) -> ()
var body: some View {
    VStack(spacing: 0){
        Button(action: {
            self.action(self.title)
        }){
            Spacer()
            Text(title.rawValue.prefix(3))
                .font(.Montserrat(weight: isSelected ? .SemiBold : .Regular, size: 16))
                .foregroundColor(isSelected ? Color.white : Color.gray)
            Spacer()
        }
    }
        .frame(width: 80, height: 40)
        .background(isSelected ? Color.white : Color.brand_purple)
}
}

2 个答案:

答案 0 :(得分:0)

通过一个视图模型更容易管理这种视图层次结构。这是一个基于您的代码的方法演示(只需用自定义字体/颜色放一些行,但这不会影响想法)。

struct ParentView_Previews: PreviewProvider {
    static var previews: some View {
        ParentView().environmentObject(ViewModel()) // inject view model
    }
}

enum MonthsTypes: String { // restored enum
    case none = "None"
    case jan = "January"
    case feb = "February"
    case mar = "March"
}

class ViewModel: ObservableObject { // selection holder (extendable for anything)
    @Published var currentMonthSelected: MonthsTypes = .none
}

struct ParentView: View {
    @EnvironmentObject var viewModel: ViewModel // assuming injected by .environmentObject(ViewModel)

    var body: some View {
        VStack {
            SingleButtonView(title: .jan) // simple declaration, action can be added
            SingleButtonView(title: .feb)
            SingleButtonView(title: .mar)
        }
    }
}

struct SingleButtonView: View {
    @EnvironmentObject var vm: ViewModel // logic on selection change is inside

    var title: MonthsTypes = .none
    var action: (MonthsTypes) -> () = { _ in } // default action does nothing

    var body: some View {
        VStack(spacing: 0){
            Button(action: {
                // change selection to self or toggle
                self.vm.currentMonthSelected = (self.vm.currentMonthSelected != self.title ? self.title : MonthsTypes.none)

                self.action(self.title) // callback if needed
            }){
                Spacer()
                Text(title.rawValue.prefix(3))
                    .foregroundColor(self.vm.currentMonthSelected == self.title ? Color.white : Color.gray)
                Spacer()
            }
        }
        .frame(width: 80, height: 40)
        .background(vm.currentMonthSelected == title ? Color.purple : Color.white)
    }
}

答案 1 :(得分:0)

enum MonthsTypes: String {
    case jan = "January"
    case feb = "February"
    case none
}

struct ContentView: View {
    @State var currentMonthSelected: MonthsTypes = .none

    var body: some View {
        VStack() {
            SingleButtonView(title: .jan, currentMonthSelected: $currentMonthSelected)

            SingleButtonView(title: .feb, currentMonthSelected: $currentMonthSelected)}

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

struct SingleButtonView: View {
    var title: MonthsTypes = .none
    @Binding var currentMonthSelected: MonthsTypes
    var isSelected: Bool {
        if title == currentMonthSelected { return true}
        return false
    }
    var body: some View {
        VStack(spacing: 0){
            Button(action: {
                self.currentMonthSelected = self.title
            }){
                Spacer()
                Text(title.rawValue.prefix(3))
                    .foregroundColor(isSelected ? Color.white : Color.gray)
                Spacer()
            }
        }
        .frame(width: 80, height: 40)
        .background(isSelected ? Color.white : Color.yellow)
    }
}