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

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

问题描述

(Xcode 11,Swift)

(Xcode 11, Swift)

作为iOS和Autolayout的新手,我正在努力实现一个相当简单的(IMHO)视图,该视图显示项目的[垂直]列表.唯一的问题是项目是动态决定的,并且每个项目都可以是文本或图像(其中的任何一个都可能很大,因此需要滚动). 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.

这是我对流程的理解:

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

这是正确的方法吗?它似乎对我不起作用(例如一个玩具示例,该示例将非常高的图像动态添加到容器视图中-我无法使滚动正常工作).在上述过程的最后一步,什么是正确的方法-只需将scrollview的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.

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

As a simple example...

1)首先添加UIScrollView(我将其设为蓝色背景以使其更易于查看).在所有四个方面将其约束为零:

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背景,以便于查看).在内容布局指南 的所有四个侧面上将其限制为零-这将(最终)定义滚动视图的内容大小.还要将其宽度和高度都限制为 框架布局指南 :

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

    }

}

如果已按照步骤进行操作,则应获得以下输出:

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

,然后滚动到底部:

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

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