在 Swift 中以编程方式创建垂直 UIScrollView
Posted
技术标签:
【中文标题】在 Swift 中以编程方式创建垂直 UIScrollView【英文标题】:Create a vertical UIScrollView programmatically in Swift 【发布时间】:2015-05-19 14:07:46 【问题描述】:我一直在寻找(工作)教程甚至是使用 UIScrollView 以编程方式垂直滚动的示例应用程序。使用故事板的教程太多了,让我不知所措。
我浏览了苹果的文档,他们的“指南”仍然没有一个可靠的例子或提示从哪里开始。到目前为止,我所做的尝试是做以下一些事情。
在课堂上直接让我的视图成为滚动视图
let scrollView = UIScrollView(frame: UIScreen.mainScreen().bounds)
然后将其分配给我的 viewDidLoad 函数中的视图
self.view = scollView
正在尝试更改内容大小。
self.scrollView.contentSize = CGSize(width:2000, height: 5678)
尝试启用滚动
scrollView.scrollEnabled = true
我能找到的关于以编程方式执行此操作的最后一个建议
override func viewDidLayoutSubviews()
super.viewDidLayoutSubviews()
scrollView.frame = view.bounds
目前我还没有尝试开始将我的对象添加到滚动视图中,(我不需要缩放,只需进行垂直滚动),但我没有设法让任何工作:(事实上,正在运行带有这些添加的应用程序只会导致 UIProblems,屏幕奇怪地向上移动,并且它不适合我的屏幕的整个宽度?我尝试修复使框架边界等于宽度,但仍然没有工作
我没有收到任何错误。
我希望看到一个可以垂直滚动的示例viewcontroller
!或者任何帮助将不胜感激!
这是灾难的截图,试图让我的视图可滚动的原因。
(我将滚动视图背景设置为红色,以查看它是否正确显示。它似乎是。但我无法滚动任何地方
按照 cmets 中的建议,我尝试添加 scrollview 作为 self.view 的子视图,而不是 self.view = self.scrollview,但没有积极的结果。
添加
scrollView.contentSize = CGSize(width:2000, height: 5678)
到 viewDidLayoutSubviews,正如下面的 cmets 中所建议的那样,我的视图可滚动!
但是由于某种原因,我的布局仍然看起来一团糟(在我让它可滚动之前,它看起来应该是这样)。
这是我的 topBar(蓝色)的示例约束,它应该占据整个水平空间。
self.scrollView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat(
"H:|[topBar]|", options: nil, metrics: nil, views: viewsDictionary))
任何想法为什么这不起作用?
【问题讨论】:
你有没有尝试过不替换当前视图,而是将scrollView添加为子视图? 我马上试试! 将其添加为子视图,并将我所有的“self.view.addsubview(..) 更改为 self.scrollView.addSubView(...),与我的约束相同。但它看起来仍然很糟糕. 让我更新一下我的帖子,用一张灾难的图片。 将self.scrollView.contentSize = CGSize(width:2000, height: 5678)
放入viewDidLayoutSubviews
并让我知道会发生什么...& 也放入viewDidAppear
...
我认为问题出在self.view = scollView
应该是self.view.addSubview(scollView)
不确定什么是快速语法但添加子视图...
【参考方案1】:
Swift 4.2
我制作了一个使用自动布局滚动堆栈视图的简单而完整的示例。
所有视图都在代码中,不需要故事板。
import UIKit
class ViewController: UIViewController
override func viewDidLoad()
super.viewDidLoad()
view.addSubview(scrollView)
scrollView.addSubview(scrollViewContainer)
scrollViewContainer.addArrangedSubview(redView)
scrollViewContainer.addArrangedSubview(blueView)
scrollViewContainer.addArrangedSubview(greenView)
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
scrollView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
scrollViewContainer.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
scrollViewContainer.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
scrollViewContainer.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
scrollViewContainer.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// this is important for scrolling
scrollViewContainer.widthAnchor.constraint(equalTo: scrollView.widthAnchor).isActive = true
let scrollView: UIScrollView =
let scrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
return scrollView
()
let scrollViewContainer: UIStackView =
let view = UIStackView()
view.axis = .vertical
view.spacing = 10
view.translatesAutoresizingMaskIntoConstraints = false
return view
()
let redView: UIView =
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 500).isActive = true
view.backgroundColor = .red
return view
()
let blueView: UIView =
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 200).isActive = true
view.backgroundColor = .blue
return view
()
let greenView: UIView =
let view = UIView()
view.heightAnchor.constraint(equalToConstant: 1200).isActive = true
view.backgroundColor = .green
return view
()
希望对您有所帮助!
【讨论】:
清晰简洁。谢谢!【参考方案2】:严格来说,我觉得问题出在下面一行。
self.view = scollView
应该是self.view.addSubview(scollView)
然后在滚动视图中添加所有标签、按钮等,然后给出内容大小。
内容大小是告诉滚动视图滚动的参数。
将self.scrollView.contentSize = CGSize(width:2000, height: 5678)
放入viewDidLayoutSubviews
。
【讨论】:
有一点。由于我仍然遇到布局问题,但这不是我最初的问题。我应该为此创建一个新问题吗? @MarkL :您将其标记为已接受是个好点。我不会赞成我接受的答案...仅在它对您有帮助且不被接受为答案的情况下才赞成... viewDidLayoutSubviews 对我来说非常有用。谢谢! @FahimParkar 你在这里写 contentSize 静态的,但我们的要求是动态的【参考方案3】:感谢Tom Insam 帮助我整理了这个答案:
您需要像往常一样添加所有约束,即
为滚动视图及其父视图添加约束。 为滚动视图的内容添加约束。然后暂停。了解这一点,即使您的 scrollView 的框架 已知为例如400 * 600,其内容的大小仍然未知。它可以是 400 * 6000 或 400 * 300 或任何其他尺寸。
没有其他基于边缘(前导、尾随、左、右、上、下、边距)的约束可用于计算滚动视图的内容大小。
除非你的视图有一些intrinsicContentSize
,那么此时如果你运行代码,你会得到一个运行时错误提示:ScrollView Content size is ambiguous强>。继续阅读以了解有关intrinsicContentSize 的更多信息。
解决办法是什么?
https://developer.apple.com/library/archive/technotes/tn2154/_index.html
要使用纯自动布局方法,请执行以下操作:
在所有涉及的视图上将translatesAutoresizingMaskIntoConstraints
设置为NO
。 使用外部到滚动视图的约束来定位和调整滚动视图的大小。 使用约束来布置滚动视图中的子视图,确保约束绑定到滚动视图的所有四个边缘,并且不要依赖滚动视图来获取它们的大小。
我加粗的部分是我回答的全部重点。您需要设置一个独立于边的(水平/垂直)约束。因为否则它将依赖滚动视图来获取其大小。
相反,您需要明确设置宽度、高度或附加到轴中心的约束。如果视图具有intrinsicContentSize,则不需要第三部分,例如标签或文本视图可以根据字体、字符长度和换行符计算其内容大小。要深入了解intrinsicContentSize,请参阅here
换个说法:
ScrollView 需要:
对其父视图的外部约束 内容的内部约束 边缘到边缘/链接子视图的高度(如果可以计算垂直滚动)。对于布局引擎,设置高度为 1000 的 contentSize 与链接多个子视图(其中所有内容的高度可以计算为 1000)没有任何不同。例如你有两个标签,它们有 400 行。每条线占用 2 点,行间距为 100 点,两个标签之间的间距为 100 点,等于 1000 ( 400 * 2 + 100 + 100) 点。你看,操作系统可以计算出 而无需查看标签的周围环境。这就是我在不依赖滚动视图的情况下计算大小的意思
另请参阅here 的文档。
【讨论】:
以上是关于在 Swift 中以编程方式创建垂直 UIScrollView的主要内容,如果未能解决你的问题,请参考以下文章
在 Swift 中以编程方式将视图添加到 stackview
在 Swift 中以编程方式创建 UITableViewController