属性 更改 SwiftUI 动画?
SwiftUI Animation on property change?
我想为列表中项目的外观设置动画。该列表如下所示:
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")
最后一个 TextField
应该隐藏到 newPersonName.count > 0
然后用动画出现。
这是代码:
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 = ""
}
}
}
}
我知道 withAnimation(...)
只适用于 participants.append(newPersonName)
,但我怎样才能使动画在 if 语句中的 属性 变化上起作用?
if ((!(self.newPersonName.count == 0 && i == self.participants.count + 1)).animation())
无效。
这是否接近您尝试构建的内容?
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
}
}
}
}
你的示例代码不会为我编译,但这是一个在 ViewModel 中使用 Combine 来控制是否根据条件出现第二个 TextField
的简单示例:
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)
}
}
}
}
我想为列表中项目的外观设置动画。该列表如下所示:
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")
最后一个 TextField
应该隐藏到 newPersonName.count > 0
然后用动画出现。
这是代码:
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 = ""
}
}
}
}
我知道 withAnimation(...)
只适用于 participants.append(newPersonName)
,但我怎样才能使动画在 if 语句中的 属性 变化上起作用?
if ((!(self.newPersonName.count == 0 && i == self.participants.count + 1)).animation())
无效。
这是否接近您尝试构建的内容?
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
}
}
}
}
你的示例代码不会为我编译,但这是一个在 ViewModel 中使用 Combine 来控制是否根据条件出现第二个 TextField
的简单示例:
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)
}
}
}
}