ios - 具有动态大小内容的 UIScrollView

标签 ios swift xcode uiscrollview storyboard

(Xcode 11、Swift)

作为 iOS 和自动布局的新手,我正在努力实现一个相当简单的(恕我直言) View ,该 View 显示一个[垂直]项目列表。唯一的问题是项目是动态决定的,每个项目都可以是文本或图像(其中任何一个都可能相当大,因此需要滚动)。 WebView 不是一个选项,因此必须在 native 实现。

这就是我对这个过程的理解:

  • 在IB中创建一个UIScrollView,并将其调整为外框的大小。
  • 将容器 View 创建为 UIScrollView 的 subview (同样,在 IB 中)并将其大小设置为相同。
  • 设置两者宽度相等的约束
  • 在运行时,使用 UILabels/UIImageView 填充容器 View ,并以编程方式设置约束以确保布局正确。
  • “告诉” ScrollView subview 的高度,以便它管理其滚动。

这是正确的方法吗?它似乎对我不起作用(对于动态添加非常高的图像到容器 View 的玩具示例 - 我无法让滚动工作)。执行上述过程中最后一步的正确方法是什么 - 只需将 ScrollView 的 contentSize 强制为填充的容器 View 的大小(它似乎对我不起作用)。任何帮助将不胜感激。

最佳答案

在运行时向 ScrollView 添加多个元素时,您可能会发现使用 UIStackView 更容易...如果设置正确,它将随着每个添加的对象自动增加高度.

作为一个简单的例子......

1) 首先添加一个 UIScrollView (我给它一个蓝色背景以使其更容易看到)。将其所有 4 条边限制为零:

enter image description here

请注意,我们看到“红色圆圈”表示缺少/冲突的约束。暂时忽略它。

2)将 UIView 作为“内容 View ”添加到 ScrollView (我给它一个 systemYellow 背景以使其更容易查看)。根据内容布局指南将其所有 4 条边都限制为零——这将(最终)定义 ScrollView 的内容大小。还要将其限制为等宽和等高框架布局指南:

enter image description here

重要步骤:选择高度约束,然后在大小检查器 Pane 中选择占位符 - 在构建时删除复选框。这将满足设计时 IB 中的自动布局,但将允许该 View 的高度根据需要缩小/增长。

3) 将垂直UIStackView添加到“内容 View ”。将其所有 4 条边限制为零。配置其属性为Fill/Fill/8(如下图):

enter image description here

4) 将 @IBOutlet 连接添加到 View Controller 类中的堆栈 View 。现在,在运行时,当您将 UI 元素添加到堆栈 View 时,所有“滚动性”都将由自动布局处理。

这是一个示例类:

class DynaScrollViewController: UIViewController {

    @IBOutlet var theStackView: UIStackView!

    override func viewDidLoad() {
        super.viewDidLoad()

        // local var so we can reuse it
        var theLabel = UILabel()
        var theImageView = UIImageView()

        // create a new label
        theLabel = UILabel()
        // this gets set to false when the label is added to a stack view,
        // but good to get in the habit of setting it
        theLabel.translatesAutoresizingMaskIntoConstraints = false
        // multi-line
        theLabel.numberOfLines = 0
        // cyan background to make it easy to see
        theLabel.backgroundColor = .cyan
        // add 9 lines of text to the label
        theLabel.text = (1...9).map({ "Line \($0)" }).joined(separator: "\n")

        // add it to the stack view
        theStackView.addArrangedSubview(theLabel)

        // add another label
        theLabel = UILabel()
        // multi-line
        theLabel.numberOfLines = 0
        // yellow background to make it easy to see
        theLabel.backgroundColor = .yellow
        // add 5 lines of text to the label
        theLabel.text = (1...5).map({ "Line \($0)" }).joined(separator: "\n")

        // add it to the stack view
        theStackView.addArrangedSubview(theLabel)

        // create a new UIImageView
        theImageView = UIImageView()
        // this gets set to false when the label is added to a stack view,
        // but good to get in the habit of setting it
        theImageView.translatesAutoresizingMaskIntoConstraints = false
        // load an image for it - I have one named background
        if let img = UIImage(named: "background") {
            theImageView.image = img
        }
        // let's give the image view a 4:3 width:height ratio
        theImageView.widthAnchor.constraint(equalTo: theImageView.heightAnchor, multiplier: 4.0/3.0).isActive = true

        // add it to the stack view
        theStackView.addArrangedSubview(theImageView)

        // add another label
        theLabel = UILabel()
        // multi-line
        theLabel.numberOfLines = 0
        // yellow background to make it easy to see
        theLabel.backgroundColor = .green
        // add 2 lines of text to the label
        theLabel.text = (1...2).map({ "Line \($0)" }).joined(separator: "\n")

        // add it to the stack view
        theStackView.addArrangedSubview(theLabel)

        // add another UIImageView
        theImageView = UIImageView()
        // this gets set to false when the label is added to a stack view,
        // but good to get in the habit of setting it
        theImageView.translatesAutoresizingMaskIntoConstraints = false
        // load a different image for it - I have one named AquariumBG
        if let img = UIImage(named: "AquariumBG") {
            theImageView.image = img
        }
        // let's give this image view a 1:1 width:height ratio
        theImageView.heightAnchor.constraint(equalTo: theImageView.widthAnchor, multiplier: 1.0).isActive = true

        // add it to the stack view
        theStackView.addArrangedSubview(theImageView)

    }

}

如果按照这些步骤操作,您应该得到以下输出:

enter image description here

滚动到底部后:

enter image description here

关于ios - 具有动态大小内容的 UIScrollView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59908454/

相关文章:

ios - 访问在界面生成器中创建的工具栏

swift - 使用 Swift 将图像上传到 Firebase 3.0 后如何正确获取图像 URL

ios - Swift 中的 Twitter 登录功能

c - MATLAB 编码器精度

ios - iOS 中的摄像头运动感应

ios - 如何使用 Xamarin for Visual Studio 2013 为我的 iOS 应用构建 IPA 文件

ios - 在 Mac/Windows 和 Iphone App 之间传输文件

ios - 使用 biometryCurrentSet iOS 更改指纹后项目不会失效

ios - 为什么需要在这个人类中添加 2 个私有(private)变量?

iphone - 统计应用程序在 xcode 中被打开的次数