【问题标题】:SwiftUI ScrollView won't center content with GeometryReaderSwiftUI ScrollView 不会使用 GeometryReader 将内容居中
【发布时间】:2020-11-12 02:26:33
【问题描述】:

我在 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))
            }
        }
    }
}

Left 是当前代码的样子,right 是我希望它的样子,无论屏幕尺寸/iPhone 型号如何。

注意这是我使用滚动视图的原因:

&lt;iframe src='https://gfycat.com/ifr/DeficientNiceInchworm' frameborder='0' scrolling='no' allowfullscreen width='400' height='210'&gt;&lt;/iframe&gt;

【问题讨论】:

    标签: ios swift swiftui scrollview geometryreader


    【解决方案1】:

    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

    【讨论】:

    【解决方案2】:

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

    图例被推到屏幕底部的原因是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
    
            }
    
        }
    
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多