SwiftUI ScrollView内容框架和偏移量

时间:2020-03-06 19:14:23

标签: scrollview swiftui

有人可以解释ScrollView测试代码的行为吗-为什么我不能滚动到左​​边缘和上边缘,为什么我可以滚动到右边缘和下边缘?以及如何解决这个问题。 (请注意,如果我们删除ISupply<T>,则行为不会改变。)

public class Covariance
{
    public class Animal { }
    public class Rabbit : Animal { }

    public interface ISupply<out T>
    {
        T Get();
    }

    public void NoCompileErrors()
    {
        ISupply<Animal> animals = null;
        ISupply<Rabbit> rabbits = null;

        animals = rabbits;
    }
}

在此图像中,我可以滚动到最左边和最左边-它不会滚动到边缘: enter image description here

但是在这里我可以滚动到底部和右侧边缘之外: enter image description here enter image description here

3 个答案:

答案 0 :(得分:1)

我已经将@Asperi的答案改编为另一个问题(SwiftUI How to align a view that's larger than screen width),并且可行。

    @State private var offset : CGPoint = .zero

    var body: some View {

        ScrollView.init([.vertical,.horizontal]) {

            VStack {
                Text("AAA")
                    .padding(8)
                    .frame(width: 1024, height: 1024)
                    .background(Color.orange)
                    .border(Color.red)
            }
            .background(rectReader())
            .offset(x: self.offset.x, y: self.offset.y)

        }
        .border(Color.blue)

    }

    func rectReader() -> some View {
        return GeometryReader { (geometry) -> AnyView in
            let offset : CGPoint = CGPoint.init(
                x: -geometry.frame(in: .global).minX,
                y: -geometry.frame(in: .global).minY
            )
            if self.offset == .zero {
                DispatchQueue.main.async {
                    self.offset = offset
                }
            }
            return AnyView(Rectangle().fill(Color.clear))
        }
    }

答案 1 :(得分:1)

或者您可以尝试对每个方向使用一个ScrollView,请尝试

import SwiftUI

struct ContentView: View {
    var body: some View {

        ScrollView(.horizontal, showsIndicators: true) {
            ScrollView(.vertical, showsIndicators: true) {
                Color.yellow.frame(width: 1024, height: 1024)
                    .overlay(Text("A").font(.largeTitle), alignment: .topLeading)
                    .overlay(Text("B").font(.largeTitle), alignment: .topTrailing)
                    .overlay(Text("C").font(.largeTitle), alignment: .bottomTrailing)
                    .overlay(Text("D").font(.largeTitle), alignment: .bottomLeading)
            }
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

更新

要了解使用.offset修饰符会发生什么,请尝试想象一下此代码段的结果

import SwiftUI

struct ContentView: View {
    var body: some View {

        HStack {
            Text("Hello").padding().background(Color.yellow).offset(x: 20, y: 40).border(Color.red)
            Text("World").padding().background(Color.pink).offset(x: -10, y: -10).border(Color.yellow)
            }.padding().border(Color.gray)

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

enter image description here

答案 2 :(得分:0)

我遇到了这个问题和答案,因为我今天试图在任何方向上滚动(缩放)图像时都在寻找这个“内容视图错放问题”的解决方案,时间长达数小时。

这里提出的解决方案都不是“不错”的,也不适合我的情况。但是在为自己找到解决方案之后,我想在这里记录如何解决您的问题。

主要问题是内容视图的中心(带有VStack元素的= {Text)与ScrollView的中心对齐。总是这样:内容大小小于还是大于ScrollView大小。 (请记住:ScrollView的大小对应于屏幕的大小,减去安全区域边缘的插图)。要将内容视图的最前边缘与滚动视图的最前边缘对齐,您必须使内容偏移当前在左侧重叠的量。

好东西:可以直接使用GeometryReader和已知的内容大小来计算它。

    var body: some View {
        GeometryReader { proxy -> AnyView in

            let insets = proxy.safeAreaInsets
            let sw = proxy.size.width + insets.leading + insets.trailing
            let sh = proxy.size.height + insets.top + insets.bottom

            let contentSize : CGFloat = 1024
            let dx: CGFloat = (contentSize > sw ? (contentSize - sw)/2 : 0.0)
            let dy: CGFloat = (contentSize > sh ? (contentSize - sh)/2 : 0.0)

            return AnyView(
                ScrollView([.vertical,.horizontal]) {
                    VStack {
                        Text("AAA")
                            .padding(8)
                            .frame(width: 1024, height: 1024)
                            .background(Color.orange)
                            .border(Color.red)
                    }
                    .offset(x: dx, y: dy)
                }
                .border(Color.blue)
            )
        }
    }