SwiftUI ScrollView无法使用GeometryReader将内容居中

zysjyyx4  于 12个月前  发布在  Swift
关注(0)|答案(3)|浏览(159)

我在SwiftUI中有一个水平的ScrollView,我想“动态”居中。scrollview中的内容将是一个动态图表,用户可以通过改变年份来改变它的宽度(5,10,15年图表水平增长)。
我有两个问题:
1.我在水平滚动视图中的内容似乎是左对齐的,任何试图用填充来居中的尝试都只是让它偏离中心,并且很难考虑各种屏幕尺寸。
1.当我尝试使用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型号。

100d 1xx 1c 1d 1x的字符串

注意这是我使用scrollview的原因:

<iframe src='https://gfycat.com/ifr/DeficientNiceInchworm' frameborder='0' scrolling='no' allowfullscreen width='400' height='210'></iframe>

m1m5dgzv

m1m5dgzv1#

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

lawou6xi

lawou6xi2#

为了正确地将图表居中在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))
            }
        }

    }

}

字符串

方案二-动态图表高度

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

        }

    }

}

iswrvxsc

iswrvxsc3#

我遇到了一个场景,我需要在ScrollView中居中一个视图,而不需要求助于GeometryReader或frame()修改器(已从SwiftUI中删除)。我的目标是保持滚动视图的功能,同时在可用空间内居中一个视图。
下面是我使用的SwiftUI代码片段:

ScrollView(.vertical, showsIndicators: false) {
    VStack(spacing: .zero) {
        // Other content...
        ViewToCenter()
            .frame(alignment: .center)
            .scaledToFill()
    }
}

字符串
在此程式码中:
我使用ScrollView和包含各种元素的VStack.frame(alignment: .center)ViewToCenter对齐到ScrollView可用空间的中心。此外,.scaledToFill()可能会影响视图的缩放行为。这种方法帮助我在ScrollView中实现所需的居中视图,而不会丢失滚动视图的功能。

相关问题