我正在使用SwiftUI开发iPhone应用程序。主网格使用嵌套在VStack中的HStack。列数在初始化时是可变的,但此后固定。行数是完全动态的。当网格扩展到超出屏幕的宽度或高度时,它将其他视图推开。
我希望它向右(在初始化时)和向下(动态)在屏幕外以及其他视图后面扩展。我尝试将所有内容放入ZStack并设置其zindice,但这没有用。有什么办法可以做到?还是我需要一种新的方法?
//
// GameView.swift
// Scoreboard
//
// Created by user926153 on 8/21/20.
// Copyright © 2020 user926153. All rights reserved.
//
//
//
/*
This uses the TrackableScrollView as created by Max Natchanon here:
https://medium.com/@maxnatchanon/swiftui-how-to-get-content-offset-from-scrollview-5ce1f84603ec
*/
import SwiftUI
import UIKit
struct ScrollOffsetPreferenceKey: PreferenceKey {
typealias Value = [CGFloat]
static var defaultValue: [CGFloat] = [0]
static func reduce(value: inout [CGFloat], nextValue: () -> [CGFloat]) {
value.append(contentsOf: nextValue())
}
}
struct TrackableScrollView<Content>: View where Content: View {
let axes: Axis.Set
let showIndicators: Bool
@Binding var contentOffset: CGFloat
let content: Content
init(_ axes: Axis.Set = .vertical, showIndicators: Bool = true, contentOffset: Binding<CGFloat>, @ViewBuilder content: () -> Content) {
self.axes = axes
self.showIndicators = showIndicators
self._contentOffset = contentOffset
self.content = content()
}
var body: some View {
GeometryReader { outsideProxy in
ScrollView(self.axes, showsIndicators: self.showIndicators) {
ZStack(alignment: self.axes == .vertical ? .top : .leading) {
GeometryReader { insideProxy in
Color.clear
.preference(key: ScrollOffsetPreferenceKey.self, value: [self.calculateContentOffset(fromOutsideProxy: outsideProxy, insideProxy: insideProxy)])
// Send value to the parent
}
VStack {
self.content
}
}
}
.onPreferenceChange(ScrollOffsetPreferenceKey.self) { value in
self.contentOffset = value[0]
}
// Get the value then assign to offset binding
}
}
private func calculateContentOffset(fromOutsideProxy outsideProxy: GeometryProxy, insideProxy: GeometryProxy) -> CGFloat {
if axes == .vertical {
return (outsideProxy.frame(in: .global).minY - insideProxy.frame(in: .global).minY) * -1
} else {
return (outsideProxy.frame(in: .global).minX - insideProxy.frame(in: .global).minX) * -1
}
}
}
struct GameView: View {
let row_label_offset: CGFloat = 80
let col_width: CGFloat = 75
let row_height: CGFloat = 50
@ObservedObject var settings: GameSettings
@State var round_number: Int = 1
@State var scores: [[Int]] = [[0, 0, 0, 0]]
@State var column_offset: CGFloat = 0
@State var row_offset: CGFloat = 0
private func AddRound() {
self.round_number += 1
self.scores.append([0, 0, 0, 0])
}
private func DeleteRound(at offsets: IndexSet) {
// NOTE: also have to delete round from score array
self.round_number -= 1
self.scores.remove(atOffsets: offsets)
}
var body: some View {
VStack {
VStack(alignment: .center, spacing: 10) {
Text("Title")
.font(.title)
Text("subtitle")
}
.border(Color.black)
VStack(alignment: .leading, spacing: 10) {
HStack {
Button(action: {
self.AddRound()
}) {
Text("New round +")
.fixedSize(horizontal: false, vertical: true)
}
.frame(width: self.row_label_offset, height: self.row_height)
TrackableScrollView(.horizontal, showIndicators: false, contentOffset: $column_offset) {
HStack {
ForEach((1...7), id: \.self) {
Text("Player \($0)\n total")
.frame(width: self.col_width, height: self.row_height)
}
}
}
.frame(height: 50)
.border(Color.red)
}
HStack {
TrackableScrollView(.vertical, showIndicators: false, contentOffset: $row_offset) {
ForEach((1...self.round_number), id: \.self) { round in
Text("Round \(round)")
.frame(width: self.col_width, height: self.row_height)
}
}
.border(Color.black)
.frame(width: self.row_label_offset)
VStack {
ForEach(self.scores, id: \.self) { round_score in
HStack {
ForEach(round_score, id: \.self) { score in
Text("\(score)")
.frame(width: self.col_width, height: self.row_height)
}
}
}
Spacer()
}
.offset(x: self.column_offset, y: self.row_offset)
Spacer()
}
.border(Color.blue)
}
Button(action: {
}) {
Text("Finish Game")
}
Spacer()
}
}
}
#if DEBUG
struct GameView_Previews: PreviewProvider {
static var previews: some View {
GameView(settings: GameSettings())
}
}
#endif
答案 0 :(得分:0)
这是固定的零件-为避免布局损坏,您必须将动态零件移出当前布局,例如。在空白区域的叠加中。还添加了一些较小的修复程序,例如剪切和对齐。
通过Xcode 12 / iOS 14测试
HStack {
TrackableScrollView(.vertical, showIndicators: false, contentOffset: $row_offset) {
ForEach((1...self.round_number), id: \.self) { round in
Text("Round \(round)")
.frame(width: self.col_width, height: self.row_height)
}
}
.border(Color.black)
.frame(width: self.row_label_offset)
Color.clear.overlay ( // << from here !!
VStack {
ForEach(self.scores, id: \.self) { round_score in
HStack {
ForEach(round_score, id: \.self) { score in
Text("\(score)")
.frame(width: self.col_width, height: self.row_height)
}
}
}
Spacer()
}
.offset(x: self.column_offset, y: self.row_offset)
, alignment: .topLeading)
.clipped()
}
.border(Color.blue)
}