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

Swift实现带固定表头与首列的非同步滚动表格方案问询

求实现带固定表头和首列的双向滚动表格(SwiftUI)

示例 示例2

我尝试了很久仍未解决,由于刚接触Swift,进展更不顺利。该表格需满足以下要求:

  • 支持横向和纵向滚动,但不能同时滚动(无斜向滚动)
  • 拥有固定表头行(滚动至表格末尾时会被“推离”)
  • 拥有固定首列

我在两款应用中见过该效果,认为实现难度应不大,但自己始终无法做好。目前我使用SwiftUI开发,考虑是否需要改用UIKit。

以下是我写的接近效果的代码:

import SwiftUI

struct Team {
    let teamId: Int
    let city: String
    let name: String
}

struct ScrollableTableView: View {
    @State private var teams = [
        Team(teamId: 1610612737, city: "Atlanta", name: "Hawks"),
        Team(teamId: 1610612738, city: "Boston", name: "Celtics"),
        Team(teamId: 1610612739, city: "Cleveland", name: "Cavaliers"),
        Team(teamId: 1610612740, city: "New Orleans", name: "Pelicans")
    ]
    
    var body: some View {
        let columns = [
            GridItem(.fixed(120), alignment: .leading), // 固定首列
            GridItem(.fixed(150), alignment: .leading),
            GridItem(.fixed(200), alignment: .leading)
        ]
        
        ScrollView([.vertical], showsIndicators: true) {
            ZStack {
                ScrollView([.horizontal]) {
                    LazyVGrid(columns: columns, alignment: .leading, pinnedViews: [.sectionHeaders]) {
                        // 固定表头区域
                        Section(header: headerView) {
                            // 表格行
                            ForEach(teams) { team in
                                Section(header: Text("") // 固定列占位
                                    .frame(height: 40)
                                    .padding(.horizontal, 4)) {
                                        
                                        Text(team.city)
                                            .frame(height: 40)
                                            .padding(.horizontal, 4)
                                            .border(Color(.separator), width: 0.5)
                                        
                                        Text(team.name)
                                            .frame(height: 40)
                                            .padding(.horizontal, 4)
                                            .border(Color(.separator), width: 0.5)
                                    }
                                    .background(Color(.systemBackground))
                            }
                        }
                    }
                }
                
                LazyVGrid(columns: [columns[0]], alignment: .leading, pinnedViews: [.sectionHeaders]) {
                    Section(header: Text("Team ID")
                        .frame(width: 120, height: 40, alignment: .leading)
                        .bold()
                        .padding(.horizontal, 4)
                        .background(Color(.systemGray5))
                        .border(Color(.separator), width: 0.5)) {
                        ForEach(teams) { team in
                            Text(String(team.teamId)) // 固定首列
                                .frame(width: 120, height: 40)
                                .padding(.horizontal, 4)
                                .background(Color(.systemGray6))
                                .border(Color(.separator), width: 0.5)
                        }
                    }
                }
            }
        }
        .border(Color(.separator), width: 1)
    }
    
    private var headerView: some View {
        HStack(spacing: 0) {
            Text("")
                .frame(width: 120, height: 40, alignment: .leading)
                .bold()
                .padding(.horizontal, 4)
                .background(Color(.systemGray5))
                .border(Color(.separator), width: 0.5)
            
            Text("City")
                .frame(width: 150, height: 40, alignment: .leading)
                .bold()
                .padding(.horizontal, 4)
                .background(Color(.systemGray5))
                .border(Color(.separator), width: 0.5)
            
            Text("Name")
                .frame(width: 200, height: 40, alignment: .leading)
                .bold()
                .padding(.horizontal, 4)
                .background(Color(.systemGray5))
                .border(Color(.separator), width: 0.5)
        }
        .background(Color(.systemGray5))
    }
}

#Preview {
    ScrollableTableView()
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 08:15:23