【问题标题】:SwiftUI - Change Text with fade animationSwiftUI - 使用淡入淡出动画更改文本
【发布时间】:2023-04-10 09:31:01
【问题描述】:

我想看看我是如何做到的,以便通过淡入和淡出更改文本视图的源代码。

因此,如果我有如下简单视图:

struct TestView: View {
    
    @State var text = "I am a shrubber."
    
    func changeText() {
        text = (text == "I am a shrubber.") ? "My name is Roger the Shrubber." : "I am a shrubber."
    }
    
    var body: some View {
        VStack {
            Text(self.text)
            TestButton(label: "Change", action: changeText)
        }
    }
    
}

如果我点击按钮,文本会立即改变。

现在,如果我将更改的代码包装在 withAnimation 块中,或者将 .animation 视图修饰符添加到 Text 视图,它只会对帧大小的更改进行动画处理。这不是我要找的:

struct TestView: View {
    
    @State var text = "I am a shrubber."
    
    func changeText() {
        withAnimation {
            text = (text == "I am a shrubber.") ? "My name is Roger the Shrubber." : "I am a shrubber."
        }
    }
    
    var body: some View {
        VStack {
            Text(self.text)
            TestButton(label: "Change", action: changeText)
        }
    }
    
}

当然,我可以通过使用.transition 视图修饰符和单独的文本字段(此答案:https://stackoverflow.com/a/60984127/5919644)来接近我正在寻找的效果,如下所示:

struct TestView: View {
    
    @State var changed = false
    
    var body: some View {
        VStack {
            if !changed {
                Text("I am a shrubber.")
                    .transition(AnyTransition.opacity.animation(.easeInOut(duration:0.3)))
            }
            if changed {
                Text("My name is Roger the Shrubber.")
                    .transition(AnyTransition.opacity.animation(.easeInOut(duration:0.3)))
            }
            
            TestButton(label: "Change", action: { self.changed.toggle() })
        }
    }
    
}

但这是一种糟糕的模式,并且不适用于任意文本更改。即便如此,淡入和淡出也会同时发生。我想让淡出/淡入顺序发生。

【问题讨论】:

  • 你试过使用动画时长吗?例如'.animation(Animation.easeInOut(duration: 3))'

标签: ios swift swiftui


【解决方案1】:

好的,所以我想我自己找到了处理这个问题的最佳方法:通过绑定的发布者观察更改,然后手动淡出、更改文本和淡出。

视图如下所示:

struct FadingTextView: View {
    
    @Binding var source: String
    var transitionTime: Double
    
    @State private var currentText: String? = nil
    @State private var visible: Bool = false
    private var publisher: AnyPublisher<[String.Element], Never> {
        source
            .publisher
            .collect()
            .eraseToAnyPublisher()
    }
    
    init(text: Binding<String>, totalTransitionTime: Double) {
        self._source = text
        self.transitionTime = totalTransitionTime / 3
    }
    
    private func update(_: Any) {
        guard currentText != nil else {
            currentText = source
            DispatchQueue.main.asyncAfter(deadline: .now() + (transitionTime)) {
                self.visible = true
            }
            return
        }
        guard source != currentText else { return }
        self.visible = false
        DispatchQueue.main.asyncAfter(deadline: .now() + (transitionTime)) {
            self.currentText = source
            DispatchQueue.main.asyncAfter(deadline: .now() + (transitionTime)) {
                self.visible = true
            }
        }
    }
    
    var body: some View {
        Text(currentText ?? "")
            .opacity(visible ? 1 : 0)
            .animation(.linear(duration: transitionTime))
            .onReceive(publisher, perform: update(_:))
    }
    
}

然后它可以用于任意文本更改,如下所示:

struct TestView: View {
    
    @State private var text: String = "Alpha"
    
    private var values: [String] = ["Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel"]
    
    private func updateText() {
        self.text = values.randomElement()!
    }
    
    var body: some View {
        VStack {
            FadingTextView(text: $text, totalTransitionTime: 1.0)
            Button("Change", action: updateText).padding()
        }
    }
}

看起来像这样:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 1970-01-01
    • 2012-08-14
    相关资源
    最近更新 更多