Swift UI列表动画:扩展具有动态高度的单元格

7

我正在尝试在SwiftUI列表中动态展开单元格,当用户点击单元格时发生此动画。然而,这个动画效果存在问题。

我遇到了这个回答(https://dev59.com/E1MH5IYBdhLWcg3w3Efb#60873883),可以帮助解决动画问题,但需要预先知道单元格展开后的期望高度。在我的情况下,这将取决于note.text中的数据:

List{
    ForEach(notes){ note in
        VStack{
            HStack{
                Text(note.title)
                    .fontWeight(.bold)
                    .foregroundColor(.gray)
                Spacer()
                Image(systemName: "chevron.right.circle")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundColor(.gray)
                    .frame(width: 20, height: 20)
            }
            .padding(.vertical)
            .contentShape(Rectangle())
            .onTapGesture{
                selectedNote = note
            }
            if isSelected(note) {
                Text(note.text)
            }
        }
        .padding([.bottom, .leading, .trailing], 20)
        .background(
            RoundedRectangle(cornerRadius: 25, style: .continuous)
                .foregroundColor(isSelected(noteSection) ? .red : .clear)
        )
        .animation(.default)
    }
    .onMove(perform: move)
}

从上面的代码中可以看出,我需要使用一个列表,以便我可以利用.onMove功能。

是否有一种方法可以获得链接答案中相同的平滑列表动画,但适用于动态扩展大小?

谢谢。


我正在为完全相同的挑战而苦苦挣扎...看到一个一年前的问题没有得到答复,感到沮丧。 - spentag
@spentag 或许这种方法适合你:https://dev59.com/vrnoa4cB1Zd3GeqPaO6L#60890312 - iMaddin
2个回答

4

我曾经为此苦苦挣扎,访问了 Stack Overflow 上的许多现有解决方案,但它们都似乎太复杂了,特别是在 2023 年。

最终我偶然发现,与其将内容放在 List 中,不如将其放在 ScrollView 中。这样,您就可以获得漂亮、干净的动画效果,而无需使用自定义高度修饰符或事先知道容器的高度。您只需要添加一些额外的样式即可使其看起来像 List 默认情况下那样漂亮。

struct Cell: View {
    @ObservedObject var item: Item
    @State var showExtra = false

    var body: some View {
        VStack {
            Text("tap me")
                .onTapGesture {
                    withAnimation{
                        showExtra.toggle()
                    }
                }
            if showExtra {
                Text("I'm extra text")
            }
        }
    }
}

struct ContenetView: View {
    var items = [ ... ] // your items
    var body: some View {
        ScrollView {
            ForEach(items) { item in
                Cell(item: item)
            }
        }
    }
}

同意,我也查了很多资料。真是太疯狂了,在2023年,列表行仍然不能像这样轻松地展开。SwiftUI应该能够与代码的预期情况相匹配,但在这个领域表现得很差。感谢你指出使用自定义ScrollView的方法。 - Gerry Shaw

0
我对SwiftUI还不太熟悉,但通过使用下面的代码,我成功实现了一些功能。如果我只是在listRow上循环使用ForEach,无法使多个listRow同时进行动画,但在这个例子中,这种方法似乎有效。也许有人可以进一步解释为什么这种方法中的动画起作用。
我觉得可能是因为列表不知道哪一行是哪一行,所以我添加了id属性。在视图中,直到id属性改变之前,我无法对任何东西进行动画处理,这就是为什么使用了onChange修饰符的原因。
希望能得到一些反馈和想法。
struct testViewTwo: View {

@State private var id1 = UUID()
@State private var id2 = UUID()

var body: some View {
    List {
        listRow(id: $id1)
        listRow(id: $id2)
    }
    .listStyle(.plain)
}}


struct listRow: View {
@Binding var id: UUID
@State private var isShowingRow: Bool = false
@State private var animateView: Bool = false

var body: some View {
    Group {
        VStack (alignment: .leading) {
            Text("\(id.uuidString)")
                .font(.caption2)
            Text("Animation test")
            Button {
                withAnimation {
                    //MARK: tirggers animation OF view
                    id = UUID()
                }
                isShowingRow.toggle()
            } label: {
                Image(systemName: "globe")
                    .imageScale(.large)
                    .foregroundColor(animateView ? .blue : .red)
                    .animation(.easeInOut(duration: 2), value: animateView)
            }
            .buttonStyle(.bordered)
            VStack {
                if isShowingRow {
                    Text("Hello, world!")
                    Text("Hello, world!")
                    Text("Hello, world!")
                }
                else {
                    EmptyView()
                }
            }
        }
        .padding()
    }
    .id(id)
    .onChange(of: id) { newValue in
        //MARK: triggers animations IN view
        animateView.toggle()
    }
}}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接