我无法消除动画故障。这是我的代码:
// Bubble.swift
import SwiftUI
struct Bubble: Identifiable {
var id = UUID()
var sender: Sender
var text: String
var value: String?
var inputType: String?
}
enum Sender {
case user
case bot
case system
}
struct BubbleView: View {
@State var bubble: Bubble
@State var showBubble = false
var body: some View {
Section {
if self.showBubble {
switch bubble.sender {
case .user, .bot:
Text(bubble.text)
.padding(10)
.foregroundColor(bubble.sender == Sender.user ? .white : .black)
.background(bubble.sender == Sender.user ? .accentColor : Color(UIColor.systemGray5))
.clipShape(RoundedRectangle(cornerRadius: 20))
.frame(maxWidth: .infinity, alignment: bubble.sender == Sender.user ? .trailing : .leading)
.padding(.vertical, bubble.sender == Sender.user ? 10 : 0)
.transition(.move(edge: .bottom))
case .system:
Text(bubble.text.uppercased())
.padding(10)
.foregroundColor(.secondary)
.font(.caption)
.fontWeight(.semibold)
.frame(maxWidth: .infinity)
.transition(.move(edge: .bottom))
}
} else {
Text("")
}
}.onAppear {
withAnimation {
self.showBubble.toggle()
}
}
}
}
#Preview {
VStack(alignment: .leading) {
BubbleView(bubble: Bubble(sender: .bot, text: "It's-a me, Mario!"))
BubbleView(bubble: Bubble(sender: .user, text: "And it's-a me, Luigi!"))
BubbleView(bubble: Bubble(sender: .system, text: "10:30"))
}
}
// Dialog.swift
import SwiftUI
struct DialogView: View {
@Binding var dialog: [Bubble]
func scrollDown(proxy: ScrollViewProxy) {
if let lastID = dialog.last?.id {
withAnimation {
proxy.scrollTo(lastID)
}
}
}
var body: some View {
ScrollViewReader { proxy in
ScrollView {
VStack(alignment: .leading) {
ForEach(dialog) { bubble in
BubbleView(bubble: bubble)
}
.onChange(of: dialog.count, initial: false) { _,_ in
scrollDown(proxy: proxy)
}
}
.frame(maxHeight: .infinity)
.padding()
Spacer()
}
}
}
}
#Preview("Dialog view") {
DialogView(dialog: .constant([
Bubble(sender: .bot, text: "Bubble 1"),
Bubble(sender: .bot, text: "Bubble 2"),
Bubble(sender: .bot, text: "Bubble 3")
]))
}
它是一个更大项目的一部分,但 DialogView 动画有缺陷:第一次出现时,发生了一些奇怪的事情。为了能够看到它,您只需创建一个新的 SwiftUI iOS 项目,并将我的代码粘贴到两个新文件中。然后,转到
Dialog.swift
文件并查看预览。第一次没有什么奇怪的事情发生,但是如果你编辑 DialogView
主体(例如评论),你会看到奇怪的动画。
它经常发生在我的更大的项目中,我不知道如何删除它。可以在模拟器上测试它,将
ContentView.swift
内容替换为以下内容:
// ContentView.swift
import SwiftUI
struct ContentView: View {
@State var bubbles: [Bubble] = []
var body: some View {
DialogView(dialog: $bubbles)
Button {
if self.bubbles.count == 0 {
self.bubbles = [
Bubble(sender: .bot, text: "Bubble 1"),
Bubble(sender: .bot, text: "Bubble 2"),
Bubble(sender: .bot, text: "Bubble 3")
]
} else {
self.bubbles = []
}
} label: {
Text("Test")
}
}
}
#Preview {
ContentView()
}
有人可以帮助我吗?谢谢!
我修改了您的示例以接受来自
TextField
的输入。当在模拟器中运行时,我看到第一条消息有一个奇怪的动画,从屏幕中间开始。后续的动画都是“向上滑动”风格的简单过渡。
要修复第一条消息的动画,我建议进行一些小更改:
.frame
设置 maxHeight: .infinity
在垂直 ScrollView
内无效。但是,设置最大宽度会很有用。
Spacer
也是多余的,可以删除。
使用
.containerRelativeFrame
将 VStack
的高度设置为 Scrollview
的高度。
// DialogView
ScrollView {
VStack(alignment: .leading) {
ForEach(dialog) { bubble in
BubbleView(bubble: bubble)
}
.onChange(of: dialog.count, initial: false) { _,_ in
scrollDown(proxy: proxy)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.containerRelativeFrame(.vertical, alignment: .top)
}
这是经过修改的
ContentView
,可用于在模拟器中进行测试:
struct ContentView: View {
@State private var dialog = [Bubble]()
@State private var text = ""
@FocusState private var hasFocus: Bool
var body: some View {
VStack {
DialogView(dialog: $dialog)
Spacer()
TextField("Text", text: $text)
.focused($hasFocus)
.padding(4)
.border(.black)
.padding()
.onSubmit {
if !text.isEmpty {
dialog.append(Bubble(sender: .bot, text: text))
text = ""
}
hasFocus = true
}
.onAppear {
hasFocus = true
}
}
}
}