每个选项卡包含网格,如何填充每个网格
With each tab containing grid, how to fill each grid
我想要一个 TabView,其中每个选项卡都是一个 LazyVGrid。我想在创建另一个选项卡之前填充特定选项卡中的每个网格,并且我希望它能够适应所看到的任何屏幕(特别是 iPad 与 iPhone)。
我有类似下面的内容:
struct ContentView: View {
var items: Items
var columns = [GridItem(.adaptive(minimum: 100))]
var body: some View {
VStack {
TabView {
ForEach((1...items.getNumPages(???)), id: \.self) {page in
VStack {
LazyVGrid(columns: columns, alignment: .leading, spacing: 10) {
ForEach(items.getItems(page: page, ???) { item in
ItemView(item: item)
}.tabItem{}.tag(page)
}.padding(.leading).padding(.trailing)
}
}
}.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
}
}
}
请注意,对于任何项目,ItemView 的大小始终相同。但是根据屏幕大小,您可能有一个包含 2 列和 40 个元素的视图,或者 3 列包含 50 个元素的视图,等等。在上面我输入了 ???传递一些会告诉我的东西:1)有多少标签(页面),2)每个标签(页面)有多少元素。我根本不需要任何滚动,只需要从一个选项卡移动到另一个选项卡的滑动行为。我想我可以加入一个 GeometryReader 并进行一系列大小计算来计算出每页适合多少项目,但是有没有更简单的方法?
谢谢。
我想到了这样的东西,我唯一要做的改变就是计算 Items struct init ()
上所有与分页相关的东西,如果你已经知道会有多少项目的话。
因为我不知道网格内项目的大小,所以我只是在每页中放置一个任意数字
import SwiftUI
struct Items{
let quantity: Int
var pager: Int = 0
var column = GridItem(.flexible(minimum: 100))
func getNumPages() -> Int{
switch UIDevice.current.userInterfaceIdiom {
case .phone:
return Int(ceil(Double(self.quantity / 50)))
case .pad:
return Int(ceil(Double(self.quantity / 100)))
@unknown default:
return Int(ceil(Double(self.quantity / 100)))
}
}
func getColums() -> [GridItem] {
switch UIDevice.current.userInterfaceIdiom {
case .phone:
return [column, column]
case .pad:
return [column, column, column]
@unknown default:
return [column, column, column]
}
}
mutating func getItems(page: Int) -> Int {
pager = page + (UIDevice.current.userInterfaceIdiom == .pad ? 100 : 50)
return pager
}
}
struct gridProblem: View {
@State var items = Items(quantity: 500)
var body: some View {
VStack {
TabView {
ForEach((0...items.getNumPages()), id: \.self) {page in
VStack {
LazyVGrid(columns: items.getColums(), alignment: .leading, spacing: 10) {
ForEach(items.pager..<items.getItems(page: Int(page))) { item in
HStack{
Spacer()
Text("\(item + self.items.pager)")
Spacer()
}.background(Color.gray)
}
}.padding(.leading).padding(.trailing)
}
.id(UUID())
.tabItem{
}.tag(page)
}
}.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
}
}
}
解决方案是使用 GeometryReader,您必须计算尺寸。还不错,关键概念是计算每列的项目数,以及根据 GeometryReader 大小计算每页的列数。绝对假定项目是固定大小的。
在我的示例中,项目只是随机生成的单词。以下适用于各种 ipad 和手机,并且在旋转设备时效果很好。
import SwiftUI
struct Items {
private let alphabet = "abcdefhijklmnopqrstuvwxyz"
private var alphaArray: [String] { return alphabet.map { String([=10=]) }}
var items: [String] = []
static let column = GridItem(.fixed(itemWidth))
static let verticalSpacing: CGFloat = 10
static let itemHeight: CGFloat = 20
static let itemWidth: CGFloat = 160
static let horizontalSpacing: CGFloat = 20
init(quantity: Int) {
for _ in 1...quantity {
let nchars = Int.random(in: 4..<16)
let tempArray = alphaArray.shuffled()
items.append( tempArray[0...nchars].joined() )
}
items.sort()
}
private func wordsPerColumn(height: CGFloat) -> Int {
var retval = Int( (height - Items.verticalSpacing) / (Items.itemHeight + Items.verticalSpacing))
// Let's remove 1, keep it roomy below.
retval -= 1
return retval
}
private func columnsPerPage(width: CGFloat) -> Int {
return Int( width / (Items.itemWidth + Items.horizontalSpacing))
}
func getPageSize(size: CGSize) -> Int {
return wordsPerColumn(height: size.height) * columnsPerPage(width: size.width)
}
func getNumPages(size: CGSize) -> Int {
var retval = items.count / getPageSize(size: size) + 1
if items.count % getPageSize(size: size) == 0 {
retval = retval - 1
}
return retval
}
func getColumns(size: CGSize) -> [GridItem] {
return [GridItem](repeating: Items.column, count: columnsPerPage(width: size.width))
}
func getItems(size: CGSize, page: Int) -> [String] {
let pageSize = getPageSize(size: size)
let startIdx = (page-1) * pageSize
let endIdx = min(startIdx + pageSize-1, items.count-1)
return Array(items[startIdx...endIdx])
}
}
struct ItemView: View {
var item: String
var body: some View {
Text(item.capitalized).frame(width: Items.itemWidth, height: Items.itemHeight, alignment: .leading).background(.orange)
}
}
struct ContentView: View {
@State var items = Items(quantity: 210)
var body: some View {
VStack {
Text("TOP")
GeometryReader { reader in
TabView {
ForEach((1...items.getNumPages(size: reader.size)), id: \.self) {page in
VStack {
LazyVGrid(columns: items.getColumns(size: reader.size), alignment: .leading, spacing: Items.verticalSpacing) {
ForEach(items.getItems(size: reader.size, page: page), id: \.self) { item in
ItemView(item: item)
}.background(Color.gray)
}.padding().border(.red, width: 3)
Spacer()
}
.id(UUID())
.tabItem{
}.tag(page)
}
}.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
}
Spacer()
}
}
}
我想要一个 TabView,其中每个选项卡都是一个 LazyVGrid。我想在创建另一个选项卡之前填充特定选项卡中的每个网格,并且我希望它能够适应所看到的任何屏幕(特别是 iPad 与 iPhone)。
我有类似下面的内容:
struct ContentView: View {
var items: Items
var columns = [GridItem(.adaptive(minimum: 100))]
var body: some View {
VStack {
TabView {
ForEach((1...items.getNumPages(???)), id: \.self) {page in
VStack {
LazyVGrid(columns: columns, alignment: .leading, spacing: 10) {
ForEach(items.getItems(page: page, ???) { item in
ItemView(item: item)
}.tabItem{}.tag(page)
}.padding(.leading).padding(.trailing)
}
}
}.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
}
}
}
请注意,对于任何项目,ItemView 的大小始终相同。但是根据屏幕大小,您可能有一个包含 2 列和 40 个元素的视图,或者 3 列包含 50 个元素的视图,等等。在上面我输入了 ???传递一些会告诉我的东西:1)有多少标签(页面),2)每个标签(页面)有多少元素。我根本不需要任何滚动,只需要从一个选项卡移动到另一个选项卡的滑动行为。我想我可以加入一个 GeometryReader 并进行一系列大小计算来计算出每页适合多少项目,但是有没有更简单的方法?
谢谢。
我想到了这样的东西,我唯一要做的改变就是计算 Items struct init ()
上所有与分页相关的东西,如果你已经知道会有多少项目的话。
因为我不知道网格内项目的大小,所以我只是在每页中放置一个任意数字
import SwiftUI
struct Items{
let quantity: Int
var pager: Int = 0
var column = GridItem(.flexible(minimum: 100))
func getNumPages() -> Int{
switch UIDevice.current.userInterfaceIdiom {
case .phone:
return Int(ceil(Double(self.quantity / 50)))
case .pad:
return Int(ceil(Double(self.quantity / 100)))
@unknown default:
return Int(ceil(Double(self.quantity / 100)))
}
}
func getColums() -> [GridItem] {
switch UIDevice.current.userInterfaceIdiom {
case .phone:
return [column, column]
case .pad:
return [column, column, column]
@unknown default:
return [column, column, column]
}
}
mutating func getItems(page: Int) -> Int {
pager = page + (UIDevice.current.userInterfaceIdiom == .pad ? 100 : 50)
return pager
}
}
struct gridProblem: View {
@State var items = Items(quantity: 500)
var body: some View {
VStack {
TabView {
ForEach((0...items.getNumPages()), id: \.self) {page in
VStack {
LazyVGrid(columns: items.getColums(), alignment: .leading, spacing: 10) {
ForEach(items.pager..<items.getItems(page: Int(page))) { item in
HStack{
Spacer()
Text("\(item + self.items.pager)")
Spacer()
}.background(Color.gray)
}
}.padding(.leading).padding(.trailing)
}
.id(UUID())
.tabItem{
}.tag(page)
}
}.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
}
}
}
解决方案是使用 GeometryReader,您必须计算尺寸。还不错,关键概念是计算每列的项目数,以及根据 GeometryReader 大小计算每页的列数。绝对假定项目是固定大小的。
在我的示例中,项目只是随机生成的单词。以下适用于各种 ipad 和手机,并且在旋转设备时效果很好。
import SwiftUI
struct Items {
private let alphabet = "abcdefhijklmnopqrstuvwxyz"
private var alphaArray: [String] { return alphabet.map { String([=10=]) }}
var items: [String] = []
static let column = GridItem(.fixed(itemWidth))
static let verticalSpacing: CGFloat = 10
static let itemHeight: CGFloat = 20
static let itemWidth: CGFloat = 160
static let horizontalSpacing: CGFloat = 20
init(quantity: Int) {
for _ in 1...quantity {
let nchars = Int.random(in: 4..<16)
let tempArray = alphaArray.shuffled()
items.append( tempArray[0...nchars].joined() )
}
items.sort()
}
private func wordsPerColumn(height: CGFloat) -> Int {
var retval = Int( (height - Items.verticalSpacing) / (Items.itemHeight + Items.verticalSpacing))
// Let's remove 1, keep it roomy below.
retval -= 1
return retval
}
private func columnsPerPage(width: CGFloat) -> Int {
return Int( width / (Items.itemWidth + Items.horizontalSpacing))
}
func getPageSize(size: CGSize) -> Int {
return wordsPerColumn(height: size.height) * columnsPerPage(width: size.width)
}
func getNumPages(size: CGSize) -> Int {
var retval = items.count / getPageSize(size: size) + 1
if items.count % getPageSize(size: size) == 0 {
retval = retval - 1
}
return retval
}
func getColumns(size: CGSize) -> [GridItem] {
return [GridItem](repeating: Items.column, count: columnsPerPage(width: size.width))
}
func getItems(size: CGSize, page: Int) -> [String] {
let pageSize = getPageSize(size: size)
let startIdx = (page-1) * pageSize
let endIdx = min(startIdx + pageSize-1, items.count-1)
return Array(items[startIdx...endIdx])
}
}
struct ItemView: View {
var item: String
var body: some View {
Text(item.capitalized).frame(width: Items.itemWidth, height: Items.itemHeight, alignment: .leading).background(.orange)
}
}
struct ContentView: View {
@State var items = Items(quantity: 210)
var body: some View {
VStack {
Text("TOP")
GeometryReader { reader in
TabView {
ForEach((1...items.getNumPages(size: reader.size)), id: \.self) {page in
VStack {
LazyVGrid(columns: items.getColumns(size: reader.size), alignment: .leading, spacing: Items.verticalSpacing) {
ForEach(items.getItems(size: reader.size, page: page), id: \.self) { item in
ItemView(item: item)
}.background(Color.gray)
}.padding().border(.red, width: 3)
Spacer()
}
.id(UUID())
.tabItem{
}.tag(page)
}
}.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
}
Spacer()
}
}
}