SwiftUI - 修复使用不带列表的可搜索时的动画跳转

Mat*_*igg 5 ios swift swiftui

希望有人知道这个动画问题的解决方案,因为我找不到让它工作的方法!

我在 ScrollView 中的 LazyVStack 中使用 ForEach。我在滚动视图上有一个 .searchable 修饰符。当我输入/取消搜索字段时,导航栏和搜索字段会向上/向下动画,但我的滚动视图会跳转而没有动画。

如果我在 .searchable 之后添加 .animation(.easeInOut) ,它会正确显示动画。然而,有两个问题,它在 iOS 15.0 中已被弃用,并且当列表项出现和过滤时,它会以疯狂的方式为列表项设置动画。

使用列表时,它也可以工作,但无法按照我需要的方式进行自定义。此问题存在于模拟器、预览版和设备中。

有谁知道我如何才能在不使用列表的情况下正确地制作动画(列表不具有列表项所需的可定制性)?

感谢您的帮助!

我正在做的重现问题的简化版本:

import SwiftUI

struct ContentView: View {
    @State var searchText: String = ""
    
    var body: some View {
        NavigationView {
            ScrollView(.vertical) {
                CustomListView()
            }
            .navigationTitle("Misbehaving ScrollView")
            .searchable(text: $searchText, placement: .automatic)
            // This .animation() will fix the issue but create many more...  
//            .animation(.easeInOut)
        }
    }
}

struct CustomListView: View {
    @State private var listItems = ["Item 0", "Item 1", "Item 2", "Item 3", "Item 4", "Item 5", "Item 6", "Item 7", "Item 8", "Item 9", "Item 10"]
    
    var body: some View {
        LazyVStack(alignment: .leading, spacing: 10) {
            ForEach(listItems, id: \.self) { item in
                CustomListItemView(item: item)
                    .padding(.horizontal)
            }
        }
    }
}

struct CustomListItemView: View {
    @State var item: String
    
    var body: some View {
        ZStack(alignment: .leading) {
            RoundedRectangle(cornerRadius: 20, style: .continuous)
                .foregroundColor(.green.opacity(0.1))
            VStack(alignment: .leading, spacing: 4) {
                Text(item)
                    .font(.headline)
                Text(item)
                    .font(.subheadline)
            }
            .padding(25)
        }
    }
}



struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
Run Code Online (Sandbox Code Playgroud)

显示相同问题的更基本示例:

import SwiftUI

struct SwiftUIView: View {
    @State var text = ""
    
    var body: some View {
        NavigationView {
            ScrollView {
                Text("1")
                Text("2")
                Text("3")
                Text("4")
                Text("5")
                Text("6")
            }
        }
        .searchable(text: $text)
    }
}

struct SwiftUIView_Previews: PreviewProvider {
    static var previews: some View {
        SwiftUIView()
    }
}
Run Code Online (Sandbox Code Playgroud)

Asp*_*eri 5

我们需要将几何ScrollView变化与可搜索文本字段的出现/消失同步动画化,正如所见,这是可动画化的。

\n

这里有两个任务:1)检测可搜索的状态变化2)ScrollView在正确的位置设置动画(以避免意外的内容动画,如问题中已经提到的)

\n

任务 1) 的一个可能的解决方案是读取isSearching环境变量:

\n
.background(\n    // read current searching state is available only in\n    // child view level environment\n    SearchingReaderView(searching: $isSearching)\n)\n\n// ...\n\nstruct SearchingReaderView: View {\n    @Binding var searching: Bool\n    @Environment(\\.isSearching) private var isSearching\n\n    var body: some View {\n        Text(" ")\n            .onChange(of: isSearching) {\n                searching = $0          // << report to p\xd0\xb0rent\n            }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

对于任务 2),是通过修改事务在转换期间注入动画:

\n
ScrollView(.vertical) {\n    CustomListView()\n}\n.transaction {\n    if isSearching || toggledSearch {\n        // increased speed to avoid views overlaping\n        $0.animation = .default.speed(1.2)\n\n        // needed to animate end of searching\n        toggledSearch.toggle()\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

使用 Xcode 13.4 / iOS 15.5 进行测试(调试慢动画以获得更好的可见性)

\n

演示

\n

GitHub 上的测试代码

\n