Swift - 如何将一堆视图放入滚动视图
Swift - How put a stack of views into a scrollview
C目前我有一个包含许多视图(UILabel、UIImageView 等)的自定义视图(returns 一个 UIStakView)。它显示良好 - 在高度足够的设备上。
(顺便说一句,这一切都是以编程方式完成的。)
在小屏幕设备上,它只会显示整个视图的顶部。所以我的解决方案是将它放在 UIScrollView 中。 (这应该很简单 - 但它让我很伤心。)
但这根本不会显示,我做错了什么/错过了什么?
部分代码如下:
override init(frame: CGRect)
{
super.init(frame: frame)
imageFrame.addSubview(prodImage)
NSLayoutConstraint.activate([
prodImage.topAnchor.constraint(equalTo: imageFrame.topAnchor),
prodImage.trailingAnchor.constraint(equalTo: imageFrame.trailingAnchor),
prodImage.leadingAnchor.constraint(equalTo: imageFrame.leadingAnchor),
prodImage.bottomAnchor.constraint(equalTo: imageFrame.bottomAnchor),
])
imageView.addSubview(imageFrame)
NSLayoutConstraint.activate([
imageFrame.topAnchor.constraint(equalTo: imageView.topAnchor),
imageFrame.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
imageFrame.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
imageFrame.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
])
// 更多浏览量...
let stack = UIStackView(arrangedSubviews: [imageView, prodName, prodPrice])
stack.axis = .vertical
stack.spacing = (self.frame.height > 400) ? (self.frame.height > 800) ? 15 : 10 : 5
stack.distribution = UIStackViewDistribution.fill
self.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
stack.topAnchor.constraint(equalTo: self.topAnchor),
// stack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
stack.widthAnchor.constraint(equalTo: self.widthAnchor),
])
}
为了进行更改,我替换了底部节:
// self.addSubview(stack)
// NSLayoutConstraint.activate([
// stack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
// stack.topAnchor.constraint(equalTo: self.topAnchor),
//// stack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
// stack.widthAnchor.constraint(equalTo: self.widthAnchor),
// ])
let scrollView = UIScrollView()
// scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stack.topAnchor.constraint(equalTo: scrollView.topAnchor),
stack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -50),
stack.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
])
self.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: self.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
scrollView.widthAnchor.constraint(equalTo: self.widthAnchor),
])
如您所见,我尝试禁用滚动视图的自动约束以使其适合它的父视图...所有尝试均失败。
如何使滚动视图可见?
可能的错误:
- 您正在将堆栈视图的前导/尾随设置为滚动视图。
- 如果打印框架,您可能会理解宽度为零
这是因为:
- 堆栈视图的宽度无法根据滚动视图确定。
- 滚动视图是一种特殊的视图,因为它的内容可以比滚动视图大。
- 因此您需要明确设置内容视图(堆栈视图)的宽度
可能的修复 1:
与其根据 scrollView
设置它,不如在 view
上设置它(假设 scrollView 作为子视图添加到 viewController 的视图)
stack.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stack.topAnchor.constraint(equalTo: view.topAnchor),
可能的修复 2:
您明确设置了堆栈视图的宽度锚点
示例:
下面给出了一个简单的示例,说明如何将堆栈视图与滚动视图一起使用。
你的大体思路是正确的。
- 滚动视图有堆栈视图
- 堆栈视图有几个子视图
屏幕截图:
一般说明:
- 滚动视图很特别,因为滚动视图的内容可以比滚动视图本身更宽和更高(允许它滚动)
- 所以内容的宽度和高度不应该绑定到滚动视图
- 内容的宽度和高度应该在滚动视图没有任何作用的情况下设置
策略
- 正如您所指出的,我喜欢使用滚动视图和内容视图
- 将实际内容添加到堆栈视图并让堆栈视图增长
- 所以只要正确设置堆栈视图对滚动视图的约束,事情就应该到位。
调试中:
- 始终打印
viewDidAppear
中的帧值以查看是否符合您的期望
示例代码:
class ViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIStackView()
let redView = UIView()
let greenView = UIView()
let yellowView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
setupContentView()
setupRedView()
setupGreenView()
setupYellowView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("scroll view = \(scrollView.frame)")
print("content view = \(contentView.frame)")
print("red view = \(redView.frame)")
print("green view = \(greenView.frame)")
print("yellow view = \(yellowView.frame)")
}
private func setupScrollView() {
scrollView.backgroundColor = .darkGray
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
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
}
private func setupContentView() {
contentView.axis = .vertical
contentView.distribution = .fill
contentView.alignment = .fill
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
//Strategy is:
//content view's leading / trailing anchors are set to view controller's view
//content view's top / bottom anchors are set to scroll view
contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
private func setupRedView() {
redView.backgroundColor = .red
redView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(redView)
}
private func setupGreenView() {
greenView.backgroundColor = .green
greenView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(greenView)
}
private func setupYellowView() {
yellowView.backgroundColor = .yellow
yellowView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(yellowView)
}
}
C目前我有一个包含许多视图(UILabel、UIImageView 等)的自定义视图(returns 一个 UIStakView)。它显示良好 - 在高度足够的设备上。
(顺便说一句,这一切都是以编程方式完成的。)
在小屏幕设备上,它只会显示整个视图的顶部。所以我的解决方案是将它放在 UIScrollView 中。 (这应该很简单 - 但它让我很伤心。)
但这根本不会显示,我做错了什么/错过了什么?
部分代码如下:
override init(frame: CGRect)
{
super.init(frame: frame)
imageFrame.addSubview(prodImage)
NSLayoutConstraint.activate([
prodImage.topAnchor.constraint(equalTo: imageFrame.topAnchor),
prodImage.trailingAnchor.constraint(equalTo: imageFrame.trailingAnchor),
prodImage.leadingAnchor.constraint(equalTo: imageFrame.leadingAnchor),
prodImage.bottomAnchor.constraint(equalTo: imageFrame.bottomAnchor),
])
imageView.addSubview(imageFrame)
NSLayoutConstraint.activate([
imageFrame.topAnchor.constraint(equalTo: imageView.topAnchor),
imageFrame.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
imageFrame.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
imageFrame.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
])
// 更多浏览量...
let stack = UIStackView(arrangedSubviews: [imageView, prodName, prodPrice])
stack.axis = .vertical
stack.spacing = (self.frame.height > 400) ? (self.frame.height > 800) ? 15 : 10 : 5
stack.distribution = UIStackViewDistribution.fill
self.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
stack.topAnchor.constraint(equalTo: self.topAnchor),
// stack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
stack.widthAnchor.constraint(equalTo: self.widthAnchor),
])
}
为了进行更改,我替换了底部节:
// self.addSubview(stack)
// NSLayoutConstraint.activate([
// stack.leadingAnchor.constraint(equalTo: self.leadingAnchor),
// stack.topAnchor.constraint(equalTo: self.topAnchor),
//// stack.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
// stack.widthAnchor.constraint(equalTo: self.widthAnchor),
// ])
let scrollView = UIScrollView()
// scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stack)
NSLayoutConstraint.activate([
stack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
stack.topAnchor.constraint(equalTo: scrollView.topAnchor),
stack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -50),
stack.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
])
self.addSubview(scrollView)
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
scrollView.topAnchor.constraint(equalTo: self.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -50),
scrollView.widthAnchor.constraint(equalTo: self.widthAnchor),
])
如您所见,我尝试禁用滚动视图的自动约束以使其适合它的父视图...所有尝试均失败。
如何使滚动视图可见?
可能的错误:
- 您正在将堆栈视图的前导/尾随设置为滚动视图。
- 如果打印框架,您可能会理解宽度为零
这是因为:
- 堆栈视图的宽度无法根据滚动视图确定。
- 滚动视图是一种特殊的视图,因为它的内容可以比滚动视图大。
- 因此您需要明确设置内容视图(堆栈视图)的宽度
可能的修复 1:
与其根据 scrollView
设置它,不如在 view
上设置它(假设 scrollView 作为子视图添加到 viewController 的视图)
stack.leadingAnchor.constraint(equalTo: view.leadingAnchor),
stack.topAnchor.constraint(equalTo: view.topAnchor),
可能的修复 2:
您明确设置了堆栈视图的宽度锚点
示例:
下面给出了一个简单的示例,说明如何将堆栈视图与滚动视图一起使用。
你的大体思路是正确的。
- 滚动视图有堆栈视图
- 堆栈视图有几个子视图
屏幕截图:
一般说明:
- 滚动视图很特别,因为滚动视图的内容可以比滚动视图本身更宽和更高(允许它滚动)
- 所以内容的宽度和高度不应该绑定到滚动视图
- 内容的宽度和高度应该在滚动视图没有任何作用的情况下设置
策略
- 正如您所指出的,我喜欢使用滚动视图和内容视图
- 将实际内容添加到堆栈视图并让堆栈视图增长
- 所以只要正确设置堆栈视图对滚动视图的约束,事情就应该到位。
调试中:
- 始终打印
viewDidAppear
中的帧值以查看是否符合您的期望
示例代码:
class ViewController: UIViewController {
let scrollView = UIScrollView()
let contentView = UIStackView()
let redView = UIView()
let greenView = UIView()
let yellowView = UIView()
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
setupContentView()
setupRedView()
setupGreenView()
setupYellowView()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
print("scroll view = \(scrollView.frame)")
print("content view = \(contentView.frame)")
print("red view = \(redView.frame)")
print("green view = \(greenView.frame)")
print("yellow view = \(yellowView.frame)")
}
private func setupScrollView() {
scrollView.backgroundColor = .darkGray
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
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
}
private func setupContentView() {
contentView.axis = .vertical
contentView.distribution = .fill
contentView.alignment = .fill
scrollView.addSubview(contentView)
contentView.translatesAutoresizingMaskIntoConstraints = false
//Strategy is:
//content view's leading / trailing anchors are set to view controller's view
//content view's top / bottom anchors are set to scroll view
contentView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
contentView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
contentView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
contentView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
}
private func setupRedView() {
redView.backgroundColor = .red
redView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(redView)
}
private func setupGreenView() {
greenView.backgroundColor = .green
greenView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(greenView)
}
private func setupYellowView() {
yellowView.backgroundColor = .yellow
yellowView.heightAnchor.constraint(equalToConstant: 400).isActive = true
contentView.addArrangedSubview(yellowView)
}
}