SwiftUI 如何为 TextField 的条件错误提示添加平滑动画?
数据小陈
错误提示通过 if 条件插入或移除时,需要设置 transition,并让状态变化发生在动画上下文中。可以将 .animation(_:value:) 放在包含输入框和提示的 VStack 上,并以“是否超出范围”作为动画触发值。这样,只有数值跨过范围边界、提示状态发生变化时,才会播放动画。
推荐写法
struct MyTestView: View {
@State private var myvacantScore: Int = 0
private var isVacantScoreOutOfRange: Bool {
myvacantScore < 0 || myvacantScore > 300
}
var body: some View {
VStack {
HStack {
Text("Vacant Score - If a team has an empty position")
Spacer()
TextField("0", value: $myvacantScore, format: .number)
.keyboardType(.numberPad)
.multilineTextAlignment(.trailing)
.frame(width: 60)
.padding(5)
.border(.black)
}
if isVacantScoreOutOfRange {
HStack {
Spacer()
Text("Vacant Score must be between 0 and 300")
.font(.footnote)
.foregroundStyle(.red)
}
.transition(
.opacity.combined(with: .move(edge: .top))
)
}
}
.animation(.easeInOut(duration: 0.2), value: isVacantScoreOutOfRange)
}
}
为什么原来的写法不够平滑
在小示例中,错误提示设置了 .transition(.scale),但没有针对相关状态变化启用动画。transition 只描述视图插入或移除时采用的效果,本身不会启动动画。
较大的示例里,.transition(.scale) 被注释掉了。.animation(.easeInOut, value: myvacantScore) 会响应每次数值变化,但提示是否出现取决于数值是否跨过范围边界。改为监听 isVacantScoreOutOfRange,动画触发条件就与提示的插入和移除相对应。
放置位置与替代方式
将 .animation(_:value:) 放在条件提示所在的容器上,可以把动画范围限制在这组视图附近。示例中的 leagueType 会让 section 在 Form 内条件插入,因此可以将动画放在 Form 上;score 提示则由所在的 VStack 单独控制。
如果其他布局通过代码直接修改状态,也可以用 withAnimation 包住修改:
withAnimation(.easeInOut(duration: 0.2)) {
myvacantScore = newScore
}
TextField 直接绑定 @State 时,通常可以先尝试前面的 .animation(_:value:) 写法。Form 的内部行布局可能影响过渡效果;如果在目标设备上仍有跳动,可以调整 transition 的组合,或把提示放进布局更可控的容器中验证。
备注:内容仅供参考。
