Par*_*war 3 ios swiftui swiftui-scrollview
我使用多向滚动视图创建了一个类似 Excel 的视图。现在我想固定标题,不仅是列标题,还有行标题。看下面的gif:
我用来创建此视图的代码:
ScrollView([.vertical, .horizontal]){
VStack(spacing: 0){
ForEach(0..<model.rows.count+1, id: \.self) {rowIndex in
HStack(spacing: 0) {
ForEach(0..<model.columns.count+1) { columnIndex in
if rowIndex == 0 && columnIndex == 0 {
Rectangle()
.fill(Color(UIColor(Color.white).withAlphaComponent(0.0)))
.frame(width: CGFloat(200).pixelsToPoints(), height: CGFloat(100).pixelsToPoints())
.padding([.leading, .trailing])
.border(width: 1, edges: [.bottom, .trailing], color: .blue)
} else if (rowIndex == 0 && columnIndex > 0) {
TitleText(
label: model.columns[columnIndex - 1].label,
columnWidth: CGFloat(columnWidth).pixelsToPoints(),
borderEgdes: [.top, .trailing, .bottom]
)
} else if (rowIndex > 0 && columnIndex == 0) {
TitleText(
label: model.rows[rowIndex - 1].label,
columnWidth: CGFloat(columnWidth).pixelsToPoints(),
borderEgdes: [.trailing, .bottom, .leading]
)
} else if (rowIndex > 0){
//text boxes
let column = model.columns[columnIndex - 1]
switch column.type {
case "Text":
MatrixTextField(keyboardType: .default)
case "Number":
MatrixTextField(keyboardType: .decimalPad)
case "RadioButton":
RadioButton()
case "Checkbox":
MatrixCheckbox()
default:
MatrixTextField(keyboardType: .default)
}
}
}
}
}
}
}
.frame(maxHeight: 500)
Run Code Online (Sandbox Code Playgroud)
是否可以在此处固定列标题和行标题?
重要的是我只使用 VStack 和 HStack 而不是 LazyVStack 和 LazyHStack,因为我需要滚动时的平滑度,当我使用 Lazy stacks 时,由于明显的原因,它会抖动很多。所以这里不能真正使用节标题。
我还可以采用什么其他方法?
Chr*_*isR 18
这比预期的要复杂一些。您必须使用 .preferenceKey 来对齐所有三个 ScollView。这是一个工作示例:
struct ContentView: View {
let columns = 20
let rows = 30
@State private var offset = CGPoint.zero
var body: some View {
HStack(alignment: .top, spacing: 0) {
VStack(alignment: .leading, spacing: 0) {
// empty corner
Color.clear.frame(width: 70, height: 50)
ScrollView([.vertical]) {
rowsHeader
.offset(y: offset.y)
}
.disabled(true)
.scrollIndicators(.hidden)
}
VStack(alignment: .leading, spacing: 0) {
ScrollView([.horizontal]) {
colsHeader
.offset(x: offset.x)
}
.disabled(true)
table
.coordinateSpace(name: "scroll")
}
}
.padding()
}
var colsHeader: some View {
HStack(alignment: .top, spacing: 0) {
ForEach(0..<columns, id: \.self) { col in
Text("COL \(col)")
.foregroundColor(.secondary)
.font(.caption)
.frame(width: 70, height: 50)
.border(Color.blue)
}
}
}
var rowsHeader: some View {
VStack(alignment: .leading, spacing: 0) {
ForEach(0..<rows, id: \.self) { row in
Text("ROW \(row)")
.foregroundColor(.secondary)
.font(.caption)
.frame(width: 70, height: 50)
.border(Color.blue)
}
}
}
var table: some View {
ScrollView([.vertical, .horizontal]) {
VStack(alignment: .leading, spacing: 0) {
ForEach(0..<rows, id: \.self) { row in
HStack(alignment: .top, spacing: 0) {
ForEach(0..<columns, id: \.self) { col in
// Cell
Text("(\(row), \(col))")
.frame(width: 70, height: 50)
.border(Color.blue)
.id("\(row)_\(col)")
}
}
}
}
.background( GeometryReader { geo in
Color.clear
.preference(key: ViewOffsetKey.self, value: geo.frame(in: .named("scroll")).origin)
})
.onPreferenceChange(ViewOffsetKey.self) { value in
print("offset >> \(value)")
offset = value
}
}
}
}
struct ViewOffsetKey: PreferenceKey {
typealias Value = CGPoint
static var defaultValue = CGPoint.zero
static func reduce(value: inout Value, nextValue: () -> Value) {
value.x += nextValue().x
value.y += nextValue().y
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4361 次 |
| 最近记录: |