我在SwiftUI中有一个水平ScrollView,我想“动态”居中。滚动视图中的内容将是一个动态图表,用户可以通过更改年份(水平分别增长5、10、15年的图表)来更改其宽度。
无论如何我有两个问题:
我在水平滚动视图中的内容似乎向左对齐,任何尝试使用填充居中的尝试都只是使它偏离居中状态,从而难以考虑各种屏幕尺寸。
当我尝试使用GeometryReader时,图表底部的“图例”被推到页面底部,而Spacer()无法解决该问题。
struct ChartView: View {
var body: some View {
VStack(alignment: .center) {
GeometryReader { geo in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(0..<self.chartSettings.getChartYears(), id:\.self) { index in
ColumnView()
}
}
}
.background(Color.gray)
.frame(maxHeight: geo.size.height/2)
}
//Chart Legend
HStack{
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)))
Text("First Value")
.font(.system(size: 12))
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.2263821661, green: 0.4659538441, blue: 0.08977641062, alpha: 1)))
Text("Second Value")
.font(.system(size: 12))
}
}
}
}
左是当前代码的外观,右是我希望的外观,无论屏幕大小/ iPhone型号如何。
注意,这是我使用滚动视图的原因:
<iframe src='https://gfycat.com/ifr/DeficientNiceInchworm' frameborder='0' scrolling='no' allowfullscreen width='400' height='210'></iframe>
答案 0 :(得分:2)
将GeometryReader
移到VStack
之外:
struct ChartView: View {
var body: some View {
GeometryReader { geo in
VStack(alignment: .center) {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(0..<self.chartSettings.getChartYears(), id:\.self) { index in
ColumnView()
}
}
}
.background(Color.gray)
.frame(maxHeight: geo.size.height/2)
//Chart Legend
HStack{
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)))
Text("First Value")
.font(.system(size: 12))
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.2263821661, green: 0.4659538441, blue: 0.08977641062, alpha: 1)))
Text("Second Value")
.font(.system(size: 12))
}
}
}
}
}
注意:水平滚动视图内容始终从左开始(不对齐)。如果您只想将HStack
放在屏幕中央,请删除ScrollView
。
答案 1 :(得分:1)
为了正确地将图表放在ScrollView
的中心,请将内容的最小宽度设置为与ScrollView
本身的宽度相同。为此,请在.frame(minWidth: geo.size.width)
内部的HStack
上调用ScrollView
。可以在here中找到此解决方案的完整说明。
图例被推到屏幕底部的原因是GeometryReader
本身就是一个视图,它会扩展以填充所有可用空间。我认为有两种解决方案可以解决此问题。
如果图表的高度是静态的,或者在渲染视图之前知道该高度,则可以使用该已知尺寸来设置GeometryReader
的高度。
struct ChartView: View {
private let chartHeight: CGFloat = 300 // declare a height parameter
var body: some View {
VStack(alignment: .center) {
GeometryReader { geo in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(0..<self.chartSettings.getChartYears(), id:\.self) { index in
ColumnView()
}
}
.frame(minWidth: geo.size.width)
}
.background(Color.gray)
}
.frame(height: chartHeight) // set the height of the GeometryReader
//Chart Legend
HStack{
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)))
Text("First Value")
.font(.system(size: 12))
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.2263821661, green: 0.4659538441, blue: 0.08977641062, alpha: 1)))
Text("Second Value")
.font(.system(size: 12))
}
}
}
}
如果您希望图表的高度是动态的,并允许ScrollView
根据内容确定其高度,则可以使用Spacers()
并在其上调用.layoutPriority(0)
方法因此,GeometryReader
和分隔符在布置其视图时具有相同的优先级。使用此解决方案,GeometryReader
只会在ScrollView
周围放置一个小的默认填充。
(可选)如果希望图例更接近ScrollView
,则可以使用负填充值。
struct ChartView: View {
var body: some View {
VStack(alignment: .center) {
Spacer().layoutPriority(0) // add a spacer above
GeometryReader { geo in
ScrollView(.horizontal, showsIndicators: false) {
HStack {
ForEach(0..<self.chartSettings.getChartYears(), id:\.self) { index in
ColumnView()
}
}
.frame(minWidth: geo.size.width)
}
.background(Color.gray)
}
//Chart Legend
HStack{
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.4666666687, green: 0.7647058964, blue: 0.2666666806, alpha: 1)))
Text("First Value")
.font(.system(size: 12))
Rectangle()
.frame(width: 10, height: 10)
.foregroundColor(Color.init(#colorLiteral(red: 0.2263821661, green: 0.4659538441, blue: 0.08977641062, alpha: 1)))
Text("Second Value")
.font(.system(size: 12))
}
.padding(.top, -20) // optionally move the legend closer to the ScrollView
Spacer().layoutPriority(0) // add a spacer below
}
}
}