I'm drawing a table using SwiftUI that has too many rows and columns to fit into the screen width / height. In this case, I cannot align the view as leading but is somehow always centered. How can I align them top leading? Here is the view that draws the table:
struct TableView: View {
let columnCount: Int = 9
let rowCount: Int = 14
var body: some View {
VStack(alignment: .leading, spacing: 20) {
ScrollView([.vertical, .horizontal], showsIndicators: false) {
GridStack(rows: self.rowCount, columns: self.columnCount) { row, col in
Text("ROW \(String(row)) COL \(String(col))")
.frame(width: 120)
}
}
}
}
}
And this is GridStack:
struct GridStack<Content: View>: View {
let rows: Int
let columns: Int
let content: (Int, Int) -> Content
var body: some View {
VStack(alignment: .leading) {
ForEach(0 ..< rows) { row in
HStack(alignment: .top) {
ForEach(0 ..< self.columns) { column in
self.content(row, column)
}
}
}
}
.padding([.top, .bottom], 20)
}
init(rows: Int, columns: Int, @ViewBuilder content: @escaping (Int, Int) -> Content) {
self.rows = rows
self.columns = columns
self.content = content
}
}
This is how it looks like in the app. Notice the edges don't fit inside the screen. Even if I try to scroll there, it just bounces back.
Here is a demo of possible approach (and direction of improvements, because I did not test all cases and possibilities)
Note: if you select only one ScrollView
axis it does content alignment automatically, otherwise it is now I assume confused, but does not have capability to be configured. So below might be considered as temporary workaround.
The idea is to read grid content offset via GeometryReader
recalculation of frame in .global.
coordinate space and mitigate it explicitly.
Also there is a try to invalidate and handle offset depending on device orientation (probably not ideal, but as a first try), because they are different.
import Combine
struct TableView: View {
let columnCount: Int = 9
let rowCount: Int = 14
@State private var offset: CGFloat = .zero
private let orientationPublisher = NotificationCenter.default.publisher(for: UIDevice.orientationDidChangeNotification)
var body: some View {
VStack(alignment: .leading, spacing: 20) {
ScrollView([.horizontal, .vertical], showsIndicators: false) {
GridStack(rows: self.rowCount, columns: self.columnCount) { row, col in
Text("ROW \(String(row)) COL \(String(col))")
.fixedSize()
.frame(width: 150)
}
.background(rectReader())
.offset(x: offset)
}
}
.onReceive(orientationPublisher) { _ in
self.offset = .zero
}
}
func rectReader() -> some View {
return GeometryReader { (geometry) -> AnyView in
let offset = -geometry.frame(in: .global).minX
if self.offset == .zero {
DispatchQueue.main.async {
self.offset = offset
}
}
return AnyView(Rectangle().fill(Color.clear))
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With