You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI下拉列表箭头旋转动画偏离中心问题求助

SwiftUI下拉列表箭头旋转时上下偏移的解决方法

问题描述

在实现SwiftUI下拉列表项时,点击列表项展开/收起时,箭头图标会出现上下偏移的问题,无法围绕自身中心点平稳旋转。相关代码如下:

struct SomeObject: Hashable {
    var title: String = "title"
    var entries: [String] = ["details", "details2", "details3"]
}

struct ContentView: View {
    var data: [SomeObject] = [SomeObject()]

    var body: some View {
        List(data, id: \.self) { item in
            HStack {
                Text(item.title)
                Spacer()
            }
            ForEach(item.entries, id: \.self) { entry in
                ListItemView(entry)
            }
        }.listStyle(.plain)
    }
}

struct ListItemView: View {
    @State var expanded: Bool = false
    @State var rotation: Double = 0
    private let entry: String

    init(_ entry: String) {
        self.entry = entry
    }

    var body: some View {
        VStack {
            Divider().frame(maxWidth: .infinity)
                .overlay(.black)
        
            HStack {
                Text(entry)
                    .fixedSize(horizontal: false, vertical: true)
                Spacer()
                Image(systemName: "chevron.down")
                    .foregroundColor(.black)
                    .padding()
                    .rotationEffect(.degrees(expanded ? 180 : 360))
                    .animation(.linear(duration: 0.3), value: expanded)
            }.padding(.horizontal)
                .padding(.vertical, 6)
        
            if expanded {
                Text("Details")
            }
        
            Divider().frame(maxWidth: .infinity)
                .overlay(.black)
        }
            .listRowSeparator(.hidden)
            .listRowInsets(.init())
            .onTapGesture {
                expanded.toggle()
            }
    }
}

解决方案

问题的核心是箭头视图在旋转过程中没有固定的尺寸边界,导致SwiftUI重新计算布局时出现位移。只需给箭头图标添加固定的frame,确保旋转时锚点稳定在自身中心即可:

修改后的ListItemView代码

struct ListItemView: View {
    @State var expanded: Bool = false
    private let entry: String

    init(_ entry: String) {
        self.entry = entry
    }

    var body: some View {
        VStack {
            Divider().frame(maxWidth: .infinity)
                .overlay(.black)
        
            HStack {
                Text(entry)
                    .fixedSize(horizontal: false, vertical: true)
                Spacer()
                Image(systemName: "chevron.down")
                    .foregroundColor(.black)
                    .frame(width: 24, height: 24) // 固定视图尺寸,确保旋转边界稳定
                    .padding()
                    .rotationEffect(.degrees(expanded ? 180 : 0)) // 用0替代360,逻辑更直观
                    .animation(.linear(duration: 0.3), value: expanded)
            }.padding(.horizontal)
                .padding(.vertical, 6)
        
            if expanded {
                Text("Details")
            }
        
            Divider().frame(maxWidth: .infinity)
                .overlay(.black)
        }
            .listRowSeparator(.hidden)
            .listRowInsets(.init())
            .onTapGesture {
                expanded.toggle()
            }
    }
}

关键修改点

  • 给Image添加.frame(width: 24, height: 24):固定箭头视图的尺寸,避免动画过程中布局边界变化导致位移
  • 将旋转角度从360改为0:360°和0°视觉效果一致,使用0°逻辑更清晰
  • 移除了未使用的rotation状态变量:简化代码结构

这样修改后,箭头会围绕自身中心点平稳旋转,不会出现上下偏移的问题。

内容的提问来源于stack exchange,提问作者Plays2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 11:01:08