具有动态大小内容的 UIScrollView [英] UIScrollView with dynamically sized content

查看:13
本文介绍了具有动态大小内容的 UIScrollView的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

(Xcode 11,斯威夫特)

(Xcode 11, Swift)

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

Being a newbie to iOS and Autolayout, I'm struggling with implementing a fairly simple (IMHO) view which displays a [vertical] list of items. The only problem is that items are decided dynamically and each of them could be either text or image (where either of those could be fairly large so scrolling would be required). WebView is not an option, so it has to be implemented natively.

我是这样理解这个过程的:

This is how I understand the process:

  • 在 IB 中创建一个 UIScrollView 并将其调整为外框的大小.
  • 将容器视图作为 UIScrollView 的子视图(同样,在 IB 中)并将其大小设置为相同.
  • 设置两个宽度相等的约束
  • 在运行时,使用 UILabels/UIImageViews 填充容器视图,并以编程方式设置约束以确保正确布局.
  • 告诉"滚动视图关于子视图的高度,以使其管理其滚动.

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

Is this the right approach? It doesn't seem to work for me (for a toy example of dynamically adding a very tall image to a container view - I cannot get the scrolling to work). What would be the proper way to do the last step in the process above - just force the contentSize of the scrollview to the size of the populated container view (it doesn't seem to work for me). Any help would be appreciated.

推荐答案

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

When adding multiple elements to a scroll view at run-time, you may find it much easier to use a UIStackView... when setup properly, it will automatically grow in height with each added object.

举个简单的例子……

1) 首先添加一个 UIScrollView (我给它一个蓝色背景以便于查看).将其在所有 4 个方面都限制为零:

1) Start by adding a UIScrollView (I gave it a blue background to make it easier to see). Constrain it to Zero on all 4 sides:

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

Note that we see the "red circle" indicating missing / conflicting constraints. Ignore that for now.

2) 在滚动视图中添加一个 UIView 作为内容视图"(我给它一个 systemYellow 背景以便于查看).在内容布局指南的所有 4 个方面将其限制为零——这将(最终)定义滚动视图的内容大小.还要将其限制为等宽和等高框架布局指南:

2) Add a UIView as a "content view" to the scroll view (I gave it a systemYellow background to make it easier to see). Constrain it to Zero on all 4 sides to the Content Layout Guide -- this will (eventually) define the scroll view's content size. Also constrain it equal width and equal height to the Frame Layout Guide:

重要步骤: 选择高度约束,然后在 Size Inspector 窗格中选择 Placeholder - Remove at build time 复选框.这将在设计时满足 IB 中的自动布局,但将允许该视图的高度根据需要缩小/增长.

Important Step: Select the Height constraint, and in the Size Inspector pane select the Placeholder - Remove at build time checkbox. This will satisfy auto-layout in IB during design time, but will allow the height of that view to shrink / grow as necessary.

3) 添加一个垂直的 UIStackView 到内容视图".将其在所有 4 个面上都约束为零.将其属性配置为Fill/Fill/8(如下图):

3) Add a Vertical UIStackView to the "content view". Constrain it to Zero on all 4 sides. Configure its properties to Fill / Fill / 8 (as shown below):

4) 在视图控制器类中添加一个 @IBOutlet 连接到堆栈视图.现在,在运行时,当您将 UI 元素添加到堆栈视图时,您的所有可滚动性"都将由自动布局处理.

4) Add an @IBOutlet connection to the stack view in your view controller class. Now, at run-time, as you add UI elements to the stack view, all of your "scrollability" will be handled by auto-layout.

这是一个示例类:

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: "
")

        // 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: "
")

        // 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: "
")

        // 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)

    }

}

如果已遵循这些步骤,您应该会得到以下输出:

If the steps have been followed, you should get this output:

并且,在滚动到底部之后:

and, after scrolling to the bottom:

这篇关于具有动态大小内容的 UIScrollView的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆