3

我在 SwiftUI 中有一个水平 ScrollView,我想“动态”居中。滚动视图中的内容将是一个动态图表,用户可以通过改变年份来改变它的宽度(5、10、15 年图表水平增长)。

无论如何,我有两个问题

  1. 我在水平滚动视图中的内容似乎是左对齐的,任何用填充将其居中的尝试都只是让它偏离居中,并且很难考虑各种屏幕尺寸。

  2. 当我尝试使用 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>

4

2 回答 2

3

为了使您的图表在 中正确居中ScrollView,请将内容的最小宽度设置为与ScrollView自身的宽度相同。为此,请调用您.frame(minWidth: geo.size.width)的. 可以在此处找到此解决方案的完整说明。HStackScrollView

图例被推到屏幕底部的原因是GeometryReader它本身就是一个扩展以填充所有可用空间的视图。我能想到的有两种解决方案可以解决这个问题。

解决方案 1 - 静态图表高度

如果图表的高度是静态的,或者如果您在渲染视图之前知道高度是多少,则可以使用该已知尺寸来设置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))
            }
        }

    }

}

解决方案 2 - 动态图表高度

如果您希望图表的高度是动态的并允许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

        }

    }

}
于 2020-10-21T01:04:00.490 回答
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

于 2020-07-22T14:04:43.330 回答