无法消除 SwiftUI 动画故障

问题描述 投票:0回答:1

我无法消除动画故障。这是我的代码:

// 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()
}

有人可以帮助我吗?谢谢!

ios swift animation swiftui transition
1个回答
0
投票

我修改了您的示例以接受来自

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
                }
        }
    }
}

Animation

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.