内容显示在底部安全区域后面,但用户可以滚动它。 这是使用
UITableView
实现的,默认情况下具有这种行为,但我需要使用带有子视图的 UIScrollView
来实现。
据我了解
UIScrollView
应该满足其超级视图。这个UIScrollView
包含“内容视图”,它也实现了它的超级视图。这个“内容视图”包含例如带有约束的UIStackView
(它只是作为示例 - 我在 XIB 中设置了约束):
stackView.bottomAnchor.constraint(greaterThanOrEqualTo: stackView.superview!.bottomAnchor)
stackView.bottomAnchor.constraint(greaterThanOrEqualTo: scrollView.safeAreaLayoutGuide.bottomAnchor)
但是在这些操作之后,滚动变得中断。
尝试更改
contentInsetAdjustmentBehavior
,但效果很奇怪,即使有足够的空间,UIScrollView
的contentSize
也会被拉伸。
您想要将滚动视图的“内容”限制为滚动视图的
Content Layout Guide
看一下这个例子...它添加了一个“全视图”滚动视图,向滚动视图添加了一个垂直堆栈视图,然后向堆栈视图添加了 10 个图像视图:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = "Wizard"
let scrollView = UIScrollView()
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 8
stackView.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(stackView)
view.addSubview(scrollView)
let cg = scrollView.contentLayoutGuide
let fg = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain all 4 sides of scroll view to view
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
// constrain all 4 sides of stack view to scroll view's Content Layout Guide
stackView.topAnchor.constraint(equalTo: cg.topAnchor),
stackView.leadingAnchor.constraint(equalTo: cg.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: cg.trailingAnchor),
stackView.bottomAnchor.constraint(equalTo: cg.bottomAnchor),
// constrain stack view width to scroll view's Frame Layout Guide width
stackView.widthAnchor.constraint(equalTo: fg.widthAnchor),
])
// generate 10 image views with images and add to the stack view
for i in 0..<10 {
let img = genImage(sz: .init(width: 200.0, height: 200.0), num: i)
let v = UIImageView(image: img)
v.heightAnchor.constraint(equalToConstant: 200.0).isActive = true
stackView.addArrangedSubview(v)
}
}
func genImage(sz: CGSize, num: Int) -> UIImage {
let colors: [UIColor] = [
.systemRed, .systemGreen, .systemBlue,
.cyan, .green, .yellow,
]
let renderer = UIGraphicsImageRenderer(size: sz)
guard let nImg = UIImage(systemName: "\(num).circle.fill") else { fatalError() }
let img = renderer.image { ctx in
colors[num % colors.count].setFill()
ctx.fill(.init(origin: .zero, size: sz))
nImg.draw(in: .init(origin: .zero, size: sz))
}
return img
}
}
看起来像这样:
滚动一下之后:
并一直滚动到底部:
编辑 - 回应评论...
您的 XIB 方法存在一些问题。
问题一:“模糊的可滚动高度”与您使用 XIB 而不是 Storyboard 的事实无关。
假设我们像这样设置一个视图控制器:
我们看到红色缺失/模糊约束错误指示器。
A
UIView
没有 size,直到我们给它一个尺寸。如果我们像这样运行应用程序,我们会看到以下内容:
粉色滚动视图,但没有蓝色“内容”视图的迹象。
现在,作为开发人员,我知道在运行时我将向该蓝色视图添加一个或多个视图(例如带有一些大标签的堆栈视图) - 具有适当的约束 - 以获得我想要的用户界面:
而且效果很好。
当使用 Storyboard / Interface Builder 布局视图时,I 知道我要在运行时做什么,但 IB 不知道。
这是一个 IB 错误/警告,我们可以安全地忽略...但是,由于我们通常不想忽略某些事情,所以解决方案是为蓝色“内容”视图提供一个内在内容大小占位符。
在尺寸检查器窗格底部附近找到它:
并更改它:
要得到这个:
现在,无需对界面进行任何其他更改,红色指示器就消失了:
您使用的实际宽度和高度值是无关紧要的...它们只是告诉 IB 我们知道我们在做什么。
问题二:尝试让滚动视图填充整个屏幕 - 包括安全区域 - 同时也让滚动视图的内容尊重安全区域:
仅当 滚动视图是控制器视图的第一个子视图时,该行为才是自动的。
如果创建 View XIB 并向其添加滚动视图,则必须在运行时“提取”滚动视图。
更简单的方法是创建一个 Empty XIB,并添加
UIScrollView
作为其“基本”视图。
我在 https://github.com/DonMag/Sample20231206 发布了一个项目,您可以看一下。