SwiftUI:实现List行的平滑向下展开动画
解决SwiftUI List行平滑展开动画问题
问题根源
原代码中使用if expanded条件渲染次要文本,会导致List行的布局结构发生突变,加上List默认的垂直居中布局,就会出现主文本先居中再跳回顶部的卡顿现象。同时,条件性移除视图会让SwiftUI重新计算整个行的布局,破坏动画流畅度。
优化方案
通过以下几点调整,在保留List完整功能的前提下实现流畅的向下展开动画:
- 强制
VStack顶部对齐,确保主文本始终固定在行顶部 - 保留次要文本视图的存在,通过
opacity和frame(height)控制显示/隐藏,避免布局结构突变 - 统一动画作用范围,让行高变化和内容显示同步过渡
修改后的完整代码
ContentView(无需改动)
struct ContentView: View { var body: some View { NavigationView { List { ForEach((1...3), id: \.self) { _ in ItemRow() } } .navigationTitle("Demo") .navigationBarTitleDisplayMode(.inline) } } }
ItemRow(核心修改)
struct ItemRow: View { @State private var expanded = false var body: some View { VStack(alignment: .leading, spacing: 8) { // 设置顶部对齐和固定间距 HStack { Text("Hello world") Spacer() Image(systemName: "chevron.forward.circle") .rotationEffect(.degrees(expanded ? 90 : 0)) .onTapGesture { withAnimation(.easeInOut(duration: 0.3)) { // 指定动画曲线和时长 expanded.toggle() } } } // 始终保留该视图,通过opacity和height控制显示 Text("Lorem ipsum dolor sit amet. Vel dicta error qui vero incidunt et fugit quisquam aut modi praesentium qui veritatis sed ipsam magnam. Ad iure velit ut possimus voluptatem cum dolores dicta. Ex cupiditate libero ut impedit internos aut reprehenderit molestias! Aut debitis dignissimos sit incidunt internos aut mollitia explicabo aut vitae numquam et repellendus iusto.") .foregroundColor(.secondary) .font(.caption) .opacity(expanded ? 1 : 0) // 透明度动画 .frame(height: expanded ? nil : 0) // 高度从0过渡到自然高度 .clipped() .animation(.easeInOut(duration: 0.3), value: expanded) // 绑定动画到expanded状态 } .listRowInsets(EdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16)) // 统一行内边距,避免跳动 .frame(maxWidth: .infinity, alignment: .top) // 确保行内容顶部对齐 } }
关键改动说明
VStack(alignment: .leading, spacing: 8):设置垂直栈的对齐方式为左对齐(顶部对齐),并固定主文本和次要文本的间距,避免展开时间距突变。- 移除
if expanded条件判断:始终渲染次要文本,通过opacity和frame(height)控制可见性,让SwiftUI只修改视图的属性而非重建布局,保证动画流畅。 - 统一动画配置:给次要文本单独绑定动画,同时在点击手势中指定动画曲线,确保旋转动画和展开动画同步。
listRowInsets和frame(maxWidth: .infinity, alignment: .top):强制行内容顶部对齐,覆盖List默认的垂直居中行为,彻底解决主文本跳动问题。
内容的提问来源于stack exchange,提问作者Jonathan
相关产品推荐
相关产品推荐

