Как условно визуализировать форму SwiftUI с анимацией, используя выбор из сегментированного средства выбора?
Я пытаюсь условно отобразить две формы на основе выбора из сегментированного средства выбора. Все отлично работает, когда нет анимации, но в тот момент, когда я добавляю ее, первая форма, кажется, ломается.
Код для 1-й формы:
struct CalculateView: View {
@Binding var checkAmount: Double
@Binding var numberOfPeople: Int
@Binding var tipPercentage: Int
@Binding var currentMode: DisplayMode
@FocusState var amountIsFocused: Bool
let tipPercentages: [Int]
var currencyType: FloatingPointFormatStyle<Double>.Currency
var grandTotal: Double
var totalPerPerson: Double
var body: some View {
Form{
Section{
TextField("Amount", value: $checkAmount, format:
.currency(code: Locale.current.currencyCode ?? "USD"))
.keyboardType(.decimalPad)
.focused($amountIsFocused)
Picker("Number of people", selection: $numberOfPeople) {
ForEach(1..<100, id: \.self){
Text($0 == 1 ? "\($0) Person" : "\($0) People")
}
}
}
Section{
Picker("Tip Percentage", selection: $tipPercentage){
ForEach(0..<101){
Text($0, format: .percent)
}
}.pickerStyle(.wheel)
} header: {
Text("How much tip do you want to leave ?")
}
Section{
HStack {
Text("Grand Total")
.foregroundColor(.secondary)
.font(.system(size:14, weight: .regular))
.textCase(.uppercase)
Spacer()
Text(grandTotal, format:
currencyType)
.foregroundColor(tipPercentage == 0 ? .red: .blue)
.font(.system(size: 20, weight: .regular))
}.padding(.horizontal, 10)
VStack(alignment: .leading){
Text("Amount per person")
.foregroundColor(.secondary)
.font(.system(size: 15, weight: .semibold))
.padding(EdgeInsets(top: 5, leading: 10, bottom: 0, trailing: 0))
.textCase(.uppercase)
Text(totalPerPerson, format:
.currency(code: Locale.current.currencyCode ?? "USD"))
.frame(maxWidth: .infinity)
.font(.system(size: 55, weight: .thin))
.padding(EdgeInsets(top: 15, leading: 0, bottom: 20, trailing: 0))
.foregroundColor(.green)
}
} header: {
Text("Final Payment")
.foregroundColor(.orange)
}
}
}
}
Код для 2-й формы:
struct HistoryView: View {
var body: some View {
Form {
Section {
Text("test")
}
}
}
}
Основной код ContentView:
enum DisplayMode: String, Equatable, CaseIterable {
case calculate
case history
}
struct ContentView: View {
@State private var checkAmount = 0.0
@State private var numberOfPeople = 2
@State private var tipPercentage = 20
@State private var currentMode: DisplayMode = .calculate
@FocusState private var amountIsFocused: Bool
let tipPercentages = [10, 15, 20, 25, 0]
var currencyType: FloatingPointFormatStyle<Double>.Currency {
return .currency(code: Locale.current.currencyCode ?? "USD")
}
var grandTotal: Double {
let tipValue = checkAmount / 100 * Double(tipPercentage)
let total = checkAmount + tipValue
return total
}
var totalPerPerson: Double {
let peopleCount = Double(numberOfPeople)
let amountPerPerson = grandTotal / peopleCount
return amountPerPerson
}
var navigationTitle: String {
let title = currentMode == .calculate ? "WeSplit" : currentMode.rawValue.capitalized
return title
}
let swapRight: AnyTransition = .asymmetric(
insertion: .move(edge: .trailing),
removal: .move(edge: .leading)
)
let swapLeft: AnyTransition = .asymmetric(
insertion: .move(edge: .leading),
removal: .move(edge: .trailing)
)
var body: some View {
NavigationView{
VStack {
if currentMode == .calculate {
CalculateView(checkAmount: $checkAmount, numberOfPeople: $numberOfPeople, tipPercentage: $tipPercentage, currentMode: $currentMode, amountIsFocused: _amountIsFocused, tipPercentages: tipPercentages, currencyType: currencyType, grandTotal: grandTotal, totalPerPerson: totalPerPerson)
.transition(swapLeft)
} else {
HistoryView()
.transition(swapRight)
}
}
.animation(.easeInOut, value: currentMode)
.navigationTitle(navigationTitle)
.toolbar{
ToolbarItemGroup(placement: .keyboard) {
Button("Done"){
amountIsFocused = false
}
}
ToolbarItemGroup(placement: .principal) {
Picker("Mode", selection: $currentMode) {
ForEach(DisplayMode.allCases, id: \.self){ mode in
Text(mode.rawValue.capitalized)
}
}.pickerStyle(.segmented)
.fixedSize()
}
ToolbarItemGroup(placement: .navigationBarTrailing) {
if currentMode == .calculate {
Button {
print("Save")
} label: {
Text("Save")
}
}
}
}
}
}
}
Вот как это выглядит на симуляторе:
1 ответ
Я могу воспроизвести проблему, похоже, это ошибка, консоль показывает некоторые предупреждения об ограничениях.
Обходной путь может использовать
TabView
. Положительным побочным эффектом является то, что вам не понадобятся пользовательские переходы, они идут с ним:
NavigationView{
TabView(selection: $currentMode) {
CalculateView(checkAmount: $checkAmount, numberOfPeople: $numberOfPeople, tipPercentage: $tipPercentage, currentMode: $currentMode, amountIsFocused: _amountIsFocused, tipPercentages: tipPercentages, currencyType: currencyType, grandTotal: grandTotal, totalPerPerson: totalPerPerson)
.tag(DisplayMode.calculate)
// .transition(swapLeft)
HistoryView()
.tag(DisplayMode.history)
// .transition(swapRight)
}
.tabViewStyle(.page(indexDisplayMode: .never) )
.animation(.easeInOut, value: currentMode)
// rest of your code as is