本文我们要在visionOS内实现一个标题输出的动画效果。主要讲ViewModifier
协议,修饰符(modifier)应用于视图或另一个视图修饰符,生成原值的另一个版本。在希望创建一个可应用于不同视图的修饰符时可实现ViewModifier协议。
首先定义ViewModel
,本例中的模型比较简单,仅定了三个变量,分别表示当前文本、标题输出是否完成以及最终的标题文本。
import SwiftUI
@Observable
class ViewModel {
var titleText: String = ""
var isTitleFinished: Bool = false
var finalTitle: String = "第三回 托内兄如海荐西宾 接外孙贾母惜孤女"
}
因模型中有默认值且需要在程序运行的过程中进行修改,所以在入口文件中需要将模型注入到环境中:
import SwiftUI
@main
struct visionOSDemoApp: App {
@State private var model = ViewModel()
var body: some Scene {
WindowGroup() {
ContentView()
.environment(model)
}
}
}
接下来就是本文的重点了,我们需要自定义一个文本修饰符。虽然可以直接将修饰符应用于视图,但更常见和地道的做法是使用修饰符来定义一个View
来包装这个视图修饰符。我们在代码里就是这么做的,在视图中我们传入了5个变量,text
和isFinished
是需要进行修改的,所以使用了Binding
,cursor
定义了光标,默认使用了常见的|
,isAnimated
表示是否显示动画。
在TypeTextModifier
中可以看到,如果isAnimated
为false
,就直接显示最终文本。而在任务中有两个for
循环,分别设置初始的光标闪烁效果以及后续逐个文字和光标交替输出的效果,最后等待片刻,标记输出结束。
import SwiftUI
extension View {
func typeText(
text: Binding<String>,
finalText: String,
isFinished: Binding<Bool>,
curor: String = "|",
isAnimated: Bool = true
) -> some View {
self.modifier(
TypeTextModifier(
text: text,
finalText: finalText,
isFinished: isFinished,
cursor: curor,
isAnimated: isAnimated
)
)
}
}
private struct TypeTextModifier: ViewModifier {
@Binding var text: String
var finalText: String
@Binding var isFinished: Bool
var cursor: String
var isAnimated: Bool
func body(content: Content) -> some View {
content
.onAppear {
if isAnimated == false {
text = finalText
isFinished = true
}
}
.task {
guard isAnimated else { return }
// Blink the cursor a few times
for _ in 1...2 {
text = cursor
try? await Task.sleep(for: .milliseconds(500))
text = ""
try? await Task.sleep(for: .milliseconds(200))
}
// Type out the title
for index in finalText.indices {
text = String(finalText.prefix(through: index)) + cursor
let milliseconds = (1 + UInt64.random(in: 0...1)) * 100
try? await Task.sleep(for: .milliseconds(milliseconds))
}
// Wrap up the title sequence
try? await Task.sleep(for: .milliseconds(400))
text = finalText
isFinished = true
}
}
}
struct ContentView: View {
@Environment(ViewModel.self) private var model
var body: some View {
@Bindable var model = model
NavigationStack {
VStack {
Spacer()
VStack {
Text(model.finalTitle)
.monospaced()
.font(.system(size: 50, weight: .bold))
.padding(.horizontal, 40)
.hidden()
.overlay(alignment: .leading) {
Text(model.titleText)
.monospaced()
.font(.system(size: 50, weight: .bold))
.padding(.leading, 40)
}
Text("林黛玉进贾府")
.font(.title)
.padding(.top, 10)
.opacity(model.isTitleFinished ? 1 : 0)
}
Spacer()
}
.typeText(text: $model.titleText, finalText: model.finalTitle, isFinished: $model.isTitleFinished, isAnimated: !model.isTitleFinished)
}
}
}
这里在屏幕中央输出两段文本,第一段会以修饰符的动画效果进行输出直至结束,第二段在第一段文本输出完成后显示。
其它相关内容请见虚拟现实(VR)/增强现实(AR)&visionOS开发学习笔记
原文地址:https://blog.csdn.net/ardor123/article/details/134837357
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_50006.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!