[英]How to animate/transition text value change in SwiftUI
我正在嘗試使用withAnimation
為文本中的值更改設置動畫,但它似乎不起作用。 我遇到了一個類似的問題,但答案不是動畫文本值。
我正在嘗試在純 SwiftUI( UIKit 示例)中重新創建此行為:
我已經嘗試過這段代碼,但它沒有為文本更改設置動畫:
struct TextAnimationView: View {
@State private var textValue = "0"
var body: some View {
VStack (spacing: 50) {
Text(textValue)
.font(.largeTitle)
.frame(width: 200, height: 200)
.transition(.opacity)
Button("Next") {
withAnimation (.easeInOut(duration: 1)) {
self.textValue = "\(Int.random(in: 1...100))"
}
}
}
}
}
我對 SwiftUI 的經驗很少,還有其他方法可以實現嗎?
提前致謝 :)
所以事實證明這真的很容易
Text(textValue)
.font(.largeTitle)
.frame(width: 200, height: 200)
.transition(.opacity)
.id("MyTitleComponent" + textValue)
請注意末尾的附加id
。 SwiftUI 使用它來決定在重繪時是否處理相同的視圖。 如果 id 不同,則假定先前的視圖已被刪除,而已添加此視圖。 因為它正在添加一個新視圖,所以它按預期應用了指定的轉換。
注意:這個 id 很可能在整個視圖樹中應該是唯一的,因此您可能需要相應地注意命名空間(因此是示例中的MyTitleComponent
前綴)。
下面是一種使用AnimatableModifier
的方法。 它只會在新值中消失。 如果您還想淡出舊值,自定義修改器並不難。 此外,由於您的顯示值是數字,您可以使用它本身作為控制變量,並進行一些小的修改。
這種方法不僅可以用於淡入淡出,還可以用於其他類型的動畫,以響應視圖值的變化。 您可以將其他參數傳遞給修飾符。 您也可以完全忽略body
傳遞的content
並創建並返回一個全新的視圖。 Overlay
、 EmptyView
等在這種情況下也很方便。
import SwiftUI
struct FadeModifier: AnimatableModifier {
// To trigger the animation as well as to hold its final state
private let control: Bool
// SwiftUI gradually varies it from old value to the new value
var animatableData: Double = 0.0
// Re-created every time the control argument changes
init(control: Bool) {
// Set control to the new value
self.control = control
// Set animatableData to the new value. But SwiftUI again directly
// and gradually varies it from 0 to 1 or 1 to 0, while the body
// is being called to animate. Following line serves the purpose of
// associating the extenal control argument with the animatableData.
self.animatableData = control ? 1.0 : 0.0
}
// Called after each gradual change in animatableData to allow the
// modifier to animate
func body(content: Content) -> some View {
// content is the view on which .modifier is applied
content
// Map each "0 to 1" and "1 to 0" change to a "0 to 1" change
.opacity(control ? animatableData : 1.0 - animatableData)
// This modifier is animating the opacity by gradually setting
// incremental values. We don't want the system also to
// implicitly animate it each time we set it. It will also cancel
// out other implicit animations now present on the content.
.animation(nil)
}
}
struct ExampleView: View {
// Dummy control to trigger animation
@State var control: Bool = false
// Actual display value
@State var message: String = "Hi" {
didSet {
// Toggle the control to trigger a new fade animation
control.toggle()
}
}
var body: some View {
VStack {
Spacer()
Text(message)
.font(.largeTitle)
// Toggling the control causes the re-creation of FadeModifier()
// It is followed by a system managed gradual change in the
// animatableData from old value of control to new value. With
// each change in animatableData, the body() of FadeModifier is
// called, thus giving the effect of animation
.modifier(FadeModifier(control: control))
// Duration of the fade animation
.animation(.easeInOut(duration: 1.0))
Spacer()
Button(action: {
self.message = self.message == "Hi" ? "Hello" : "Hi"
}) {
Text("Change Text")
}
Spacer()
}
}
}
struct ExampleView_Previews: PreviewProvider {
static var previews: some View {
ExampleView()
}
}
我找不到通過淡入淡出為文本值設置動畫的方法。 設置Text
的動畫屬性時,您將在動畫時看到三個點 (...)。
至於現在我想出了一個可以改變不透明度的工作:
@State private var textValue: Int = 1
@State private var opacity: Double = 1
var body: some View {
VStack (spacing: 50) {
Text("\(textValue)")
.font(.largeTitle)
.frame(width: 200, height: 200)
.opacity(opacity)
Button("Next") {
withAnimation(.easeInOut(duration: 0.5), {
self.opacity = 0
})
self.textValue += 1
withAnimation(.easeInOut(duration: 1), {
self.opacity = 1
})
}
}
}
當您更改它時,這將淡出並淡入文本。
這是使用標准轉換的方法。 字體大小、幀、動畫持續時間可根據您的需要進行配置。 演示僅包括重要的方法。
struct TestFadeNumbers: View {
@State private var textValue: Int = 0
var body: some View {
VStack (spacing: 50) {
if textValue % 2 == 0 {
Text("\(textValue)")
.font(.system(size: 200))
.transition(.opacity)
}
if textValue % 2 == 1 {
Text("\(textValue)")
.font(.system(size: 200))
.transition(.opacity)
}
Button("Next") {
withAnimation(.linear(duration: 0.25), {
self.textValue += 1
})
}
Button("Reset") {
withAnimation(.easeInOut(duration: 0.25), {
self.textValue = 0
})
}
}
}
}
如果@Tobias Hesselink 的代碼不起作用,請考慮使用:
VStack {
Text(文本)
.transition(AnyTransition.opacity.combined(with: .slide))
.id("MyTitleComponent" + 文本)
Button("Button") {
withAnimation(.easeInOut(duration: 1.0)) {
文本 = "NewText"
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.