fix: reduce memory footprint — Canvas for dot grid, scope PreferenceKey
DotGridProgress replaced GeometryReader + 200+ Circle view nodes with a single Canvas draw call. Canvas receives its own size parameter so no GeometryReader is needed; SwiftUI interpolates the progress value through the .animation modifier for smooth fill transitions. FloatingTabState ScrollYKey made private to TabBarScrollModifier to limit its PreferenceKey scope and prevent unintended propagation across unrelated subtrees.
This commit is contained in:
@@ -1107,39 +1107,29 @@ struct DotGridProgress: View {
|
|||||||
private let rows = 7
|
private let rows = 7
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
GeometryReader { geo in
|
Canvas { ctx, size in
|
||||||
let cols = max(1, Int((geo.size.width + gap) / (dotSize + gap)))
|
let step = dotSize + gap
|
||||||
|
let cols = max(1, Int((size.width + gap) / step))
|
||||||
let total = cols * rows
|
let total = cols * rows
|
||||||
let filled = Int(Double(total) * min(max(progress, 0), 1))
|
let filled = Int(Double(total) * min(max(progress, 0), 1))
|
||||||
|
|
||||||
VStack(alignment: .leading, spacing: gap) {
|
for row in 0..<rows {
|
||||||
ForEach(0..<rows, id: \.self) { row in
|
for col in 0..<cols {
|
||||||
DotRow(cols: cols, rowStart: row * cols, filled: filled,
|
let idx = row * cols + col
|
||||||
dotSize: dotSize, gap: gap, cs: cs)
|
let rect = CGRect(
|
||||||
|
x: CGFloat(col) * step,
|
||||||
|
y: CGFloat(row) * step,
|
||||||
|
width: dotSize, height: dotSize
|
||||||
|
)
|
||||||
|
ctx.fill(
|
||||||
|
Path(ellipseIn: rect),
|
||||||
|
with: .color(idx < filled ? AppColors.green : AppColors.green.opacity(0.12))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.animation(KisaniSpring.entrance, value: filled)
|
|
||||||
}
|
|
||||||
.frame(height: CGFloat(rows) * dotSize + CGFloat(rows - 1) * gap)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct DotRow: View {
|
|
||||||
let cols: Int
|
|
||||||
let rowStart: Int
|
|
||||||
let filled: Int
|
|
||||||
let dotSize: CGFloat
|
|
||||||
let gap: CGFloat
|
|
||||||
let cs: ColorScheme
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
HStack(spacing: gap) {
|
|
||||||
ForEach(0..<cols, id: \.self) { col in
|
|
||||||
let isFilled = (rowStart + col) < filled
|
|
||||||
Circle()
|
|
||||||
.fill(isFilled ? AppColors.green : AppColors.green.opacity(0.12))
|
|
||||||
.frame(width: dotSize, height: dotSize)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
.frame(maxWidth: .infinity)
|
||||||
|
.frame(height: CGFloat(rows) * (dotSize + gap) - gap)
|
||||||
|
.animation(KisaniSpring.entrance, value: progress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user