๐problem with .readSize()
Last updated
Last updated
โญ๏ธ ๅปบ่ญฐ๏ผๆญคๆนๆณๆๆนๅ็บ .onChangeSize() ๆ่ฝ็ฌฆๅ็จๅผ็ขผ็ๅๆใ
โ๏ธ .readSize() ็ๅคงๅ้ก๏ผ
็ถๆฌไพไธญ็ idealCellAspectRatio
ๆน่ฎๆ๏ผrows
, cols
, ratio
ๅปๆฒ็ผ็ไปปไฝ่ฎๅ๏ผ ้ไธป่ฆๆฏๅ ็บ size
ไธฆๆฒๆ่ฎๅ๏ผ็ถ่ .readSize() ่ๅพ็้ไฝๆฉๅถๆฏ้้ PreferenceKey (.onPreferenceChange())ไพๆไฝ็๏ผ่ฅ size
ๆฒๆ็ผ็่ฎๅ๏ผPreferenceKey ่ช็ถไธๆ่จญๅฎๆฐ็ๅผ๏ผๅ ๆญคไนไธๆ่งธ็ผ .readSize() ็ onChange
closure๏ผ่ฃก้ข็่จ็ฎ่ช็ถ่ขซ่ทณ้๏ผๆไปฅไนไธๆๆดๆฐ rows
, cols
, ratio
็ญ่ฎๆธ โ๏ธโ๏ธโ๏ธ
๐ ่งฃ่ฅ๏ผ
ไธ่ฆ้้ PreferenceKey๏ผ็ดๆฅ็จ GeometryReaderโ๏ธ
(่จป๏ผ็พๅจๅทฒ็ถๅ ่ฃๅจ .getSize() ่ฃก้ขใ)
// ๐ ่งฃ่ฅ๏ผGeometryReader
.getSize { size in
// recompute the current layout
let layout = MyGrid<Int, Text>.Layout(
idealCellAspectRatio, count: items.count, in: size
)
// update view states
rows = layout.rows
cols = layout.cols
ratio = layout.cellSize.aspectRatio
}
โฌ๏ธ ้่ฆ๏ผ SlidersForSize, (Revised from MyGrid)
// 2022.02.17 (+) add slider for ideal cell ratio, found bug of .readSize()
import SwiftUI
struct TestMyGrid: View {
@State private var size = CGSize(300, 200) // proposed size
@State private var ratio: CGFloat = 1 // current cell aspect ratio
@State private var rows = 0 // current # of rows
@State private var cols = 0 // current # of cols
@State private var idealCellAspectRatio: CGFloat = 1
let items = Array(1...10)
var body: some View {
VStack {
ScrollView {
myGrid.padding(40)
}
controls
}
}
}
extension TestMyGrid {
var myGrid: some View {
// ๐ MyGrid<Item, ItemView>
MyGrid(
items: items, // โญ๏ธ Item == Int (require: Int: Identifiable)
cellAspectRatio: idealCellAspectRatio
)
{ i in // โญ๏ธ viewForItem: (Item) -> ItemView
Color.purple
.border(.black)
.overlay { Text("\(i)").bold().shadow(radius: 3) }
}
// โญ๏ธ read proposed size from parent (.frame() modifier)
// ------------------------------------------------------------------------
// โ๏ธ .readSize() ็ๅคงๅ้ก๏ผ
// ็ถๆฌไพไธญ็ idealCellAspectRatio ๆน่ฎๆ๏ผrows, cols, ratio ๅปๆฒ็ผ็ไปปไฝ่ฎๅ๏ผ
// ้ไธป่ฆๆฏๅ ็บ size ไธฆๆฒๆ่ฎๅ๏ผ็ถ่ .readSize() ่ๅพ็้ไฝๆฉๅถๆฏ้้ PreferenceKey
// ไพๆไฝ็๏ผ่ฅ size ๆฒๆ็ผ็่ฎๅ๏ผPreferenceKey ่ช็ถไธๆ่จญๅฎๆฐ็ๅผ๏ผๅ ๆญคไนไธๆ่งธ็ผ
// .readSize() ็ `onChange` closure๏ผๆไปฅๅจ้ๅ closure ่ฃก้ข็่จ็ฎไนๅฐฑ่ช็ถๅฐ
// ่ขซ่ทณ้๏ผๆไปฅไนไธๆๆดๆฐ rows, cols, ratio ็ญ่ฎๆธ โ๏ธโ๏ธโ๏ธ
// ------------------------------------------------------------------------
.readSize { size in
let layout = MyGrid<Int, Text>.Layout(
idealCellAspectRatio, count: items.count, in: size
)
rows = layout.rows
cols = layout.cols
ratio = layout.cellSize.aspectRatio
}
// ---------------------------------------------------------------
// ๐ ่งฃ่ฅ๏ผ
// ไธ่ฆ้้ PreferenceKey๏ผ็ดๆฅ็จ GeometryReaderโ๏ธ
// โญ๏ธ ๆณจๆ๏ผ
// ๅฆๆ็ดๆฅไฝฟ็จ `.overlay{ emptyView }`๏ผไธ็จ GeometryReader ็่ฉฑ๏ผ
// ๅพ็ฅๅฅ็ๆฏ๏ผrows, cols, ratio ไพ็ถไธๆๆดๆฐโ๏ธโ๏ธโ๏ธ
// ๆๅฅ่ฉฑ่ชช๏ผGeometryReader ๆๆๅ
ถไป View ๆๆฒๆ็ใ็ฅๅฅๅ่ฝใใ
// ---------------------------------------------------------------
// .overlay {
// GeometryReader { _ in emptyView }
// }
// โญ๏ธ parent's proposed size
.frame(size)
.dimension(.topLeading, arrow: .blue, label: .orange)
.shadowedBorder()
.padding(.bottom, 40)
}
// ๐ ่งฃ่ฅ๏ผempty view
var emptyView: some View {
let layout = MyGrid<Int, Text>.Layout(
idealCellAspectRatio, count: items.count, in: size
)
rows = layout.rows
cols = layout.cols
ratio = layout.cellSize.aspectRatio
return EmptyView()
}
/// view controls
var controls: some View {
VStack {
Text("Cells try to maintain their aspect ratio.")
.font(.title3)
Group {
Text("ideal cell aspect ratio = \(idealCellAspectRatio.decimalPlaces(2))")
VStack {
Text("current cell aspect ratio = \(ratio.decimalPlaces(2))")
Text("rows: \(rows), cols: \(cols)")
}
.border(.pink)
}
.font(.caption).foregroundColor(.secondary)
HStack(alignment: .top, spacing: 40) {
// control ideal cell aspect ratio
SliderWithSubtitle(
value: $idealCellAspectRatio,
range: 0.3...3, step: 0.01,
subtitle: "ideal ratio",
decimalPlaces: 2,
tint: .green
)
// control proposed size
SlidersForSize($size)
}
}
.padding()
}
}
struct TestMyGrid_Previews: PreviewProvider {
static var previews: some View {
TestMyGrid()
}
}
this topic involves GeometryReader and PreferenceKey.
this is a problem of .readSize().
can be fixed with .getSize().
revised from MyGrid.
problem with nested types in Generic Types, ๐ to nest or not to nestโ
2022.02.18
็พๅจๅทฒ็ถๅ ่ฃๆไธๅ view extension: .getSize()
// ๐ ่งฃ่ฅ๏ผGeometryReader
.overlay {
GeometryReader { _ in emptyView }
}
// ๐ ่งฃ่ฅ๏ผ(normal code inside GeometryReader's closure)
var emptyView: some View {
let layout = MyGrid<Int, Text>.Layout(
idealCellAspectRatio, count: items.count, in: size
)
rows = layout.rows
cols = layout.cols
ratio = layout.cellSize.aspectRatio
return EmptyView()
}
โญ๏ธ ๆณจๆ๏ผ
ๅฆๆ็ดๆฅ็จ .overlay{ emptyView }
๏ผไธ็จ GeometryReader ็่ฉฑ๏ผๅพ็ฅๅฅ็ๆฏ๏ผrows
, cols
, ratio
ไพ็ถไธๆๆดๆฐโ๏ธโ๏ธโ๏ธ