0

I want to animate the appearance of an item in a list. The list looks like this:

Text("Jim") Text("Jonas") TextField("New Player") TextField("New Player") //should be animated when appearing (not shown until a name is typed in the first "New Player") 

The last TextField should be hidden until newPersonName.count > 0 and then appear with an animation.

This is the code:

struct V_NewSession: View { @State var newPersonName: String = "" @State var participants: [String] = [ "Jim", "Jonas" ] var body: some View { VStack(alignment: .leading) { ForEach(0...self.participants.count + 1, id: \.self) { i in // Without this if statement, the animation works // but the Textfield shouldn't be shown until a name is typed if (!(self.newPersonName.count == 0 && i == self.participants.count + 1)) { HStack { if(i < self.participants.count) { Text(self.participants[i]) } else { TextField("New Player", text: $newPersonName, onEditingChanged: { focused in if (self.newPersonName.count == 0) { if (!focused) { handleNewPlayerEntry() } } }) } } } } .transition(.scale) Spacer() } } func handleNewPlayerEntry() { if(newPersonName.count > 0) { withAnimation(.spring()) { participants.append(newPersonName) newPersonName = "" } } } } 

I know withAnimation(...) only applies to participants.append(newPersonName), but how can I get the animation to work on the property change in the if-statement? if ((!(self.newPersonName.count == 0 && i == self.participants.count + 1)).animation()) doesn't work.

1
  • I updated it and it compiles now Commented Jun 7, 2021 at 6:53

2 Answers 2

2

Your example code won't compile for me, but here's a trivial example of using Combine inside a ViewModel to control whether a second TextField appears based on a condition:

 import SwiftUI import Combine class ViewModel : ObservableObject { @Published var textFieldValue1 = "" @Published var textFieldValue2 = "Second field" @Published var showTextField2 = false private var cancellable : AnyCancellable? init() { cancellable = $textFieldValue1.sink { value in withAnimation { self.showTextField2 = !value.isEmpty } } } } struct ContentView: View { @StateObject var viewModel = ViewModel() var body: some View { VStack { TextField("", text: $viewModel.textFieldValue1) .textFieldStyle(RoundedBorderTextFieldStyle()) if viewModel.showTextField2 { TextField("", text: $viewModel.textFieldValue2) .textFieldStyle(RoundedBorderTextFieldStyle()) .transition(.scale) } } } } 
Sign up to request clarification or add additional context in comments.

Comments

0

Is that approaching what you're attempting to build ?

struct ContentView: View { @State var newPersonName: String = "" @State var participants: [String] = [ "Jim", "Jonas" ] @State var editingNewPlayer = false var body: some View { VStack(alignment: .leading, spacing: 16) { ForEach(participants, id: \.self) { participant in Text(participant) .padding(.trailing) Divider() } Button(action: handleNewPlayerEntry, label: { TextField("New Player", text: $newPersonName, onEditingChanged: { edit in editingNewPlayer = edit }, onCommit: handleNewPlayerEntry) }) if editingNewPlayer { Button(action: handleNewPlayerEntry, label: { TextField("New Player", text: $newPersonName) { edit in editingNewPlayer = false } }) } } .padding(.leading) .frame(maxHeight: .infinity, alignment: .top) .transition(.opacity) .animation(.easeIn) } func handleNewPlayerEntry() { if newPersonName.count > 0 { withAnimation(.spring()) { participants.append(newPersonName) newPersonName = "" editingNewPlayer = false } } } } 

1 Comment

You might be on to the right answer, but since you didn't explain your code, we don't know. Perhaps you can explain your solution?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.