[英]Swift: How to fill a ScrollView from Interface Builder with UIViews programmatically
I am working on a project where I want the user to be able to select two methods of input for the same form.我正在开发一个项目,我希望用户能够使用 select 为同一表单提供两种输入方法。 I came up with a scrollview that contains two custom UIViews (made programmatically).我想出了一个包含两个自定义 UIView(以编程方式制作)的滚动视图。 Here is the code for the responsible view controller:这是负责视图 controller 的代码:
import UIKit
class MainVC: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
var customView1: CustomView1 = CustomView1()
var customView2: customView2 = CustomView2()
var frame = CGRect.zero
func setupScrollView() {
pageControl.numberOfPages = 2
frame.origin.x = 0
frame.size = scrollView.frame.size
customView1 = customView1(frame: frame)
self.scrollView.addSubview(customView1)
frame.origin.x = scrollView.frame.size.width
frame.size = scrollView.frame.size
customView2 = CustomView2(frame: frame)
self.scrollView.addSubview(customView2)
self.scrollView.contentSize = CGSize(width: scrollView.frame.size.width * 2, height: scrollView.frame.size.height)
self.scrollView.delegate = self
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(pageNumber)
}
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
scrollView.delegate = self
}
While it works, Xcode gives me an error message for auto layout:虽然它有效,但 Xcode 给了我一条自动布局的错误消息:
Scrollable content size is ambiguous for "ScrollView" “ScrollView”的可滚动内容大小不明确
Also a problem: content on the second UIView is not centered, even though it should be:还有一个问题:第二个 UIView 上的内容没有居中,即使它应该是:
picture of the not centered content未居中内容的图片
import UIKit
class customView2: UIView {
lazy var datePicker: UIDatePicker = {
let datePicker = UIDatePicker()
datePicker.translatesAutoresizingMaskIntoConstraints = false
return datePicker
}()
//initWithFrame to init view from code
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
//initWithCode to init view from xib or storyboard
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setupView()
}
func setupView () {
self.backgroundColor = .systemYellow
datePicker.datePickerMode = .date
datePicker.addTarget(self, action: #selector(self.datePickerValueChanged(_:)), for: .valueChanged)
addSubview(datePicker)
setupLayout()
}
func setupLayout() {
let view = self
NSLayoutConstraint.activate([
datePicker.centerXAnchor.constraint(equalTo: view.centerXAnchor),
datePicker.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
datePicker.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.5),
datePicker.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.2)
])
}
@objc func datePickerValueChanged(_ sender: UIDatePicker) {
let dateFormatter: DateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd.MM.yyyy"
let selectedDate: String = dateFormatter.string(from: sender.date)
print("Selected value \(selectedDate)")
}
Any ideas on how to solve this?关于如何解决这个问题的任何想法? Thank you very much in advance.非常感谢您提前。 And please go easy on me, this is my first question on stackoverflow.请 go 对我轻松一点,这是我在 stackoverflow 上的第一个问题。 I am also fairly new to programming in swift.我对 swift 中的编程也相当陌生。
To make things easier on yourself,为了让自己更轻松,
UIStackView
to the scroll view将水平UIStackView
添加到滚动视图.distribution =.fillEqually
设置.distribution =.fillEqually
.contentLayoutGuide
将所有 4 面约束到滚动视图的.contentLayoutGuide
.frameLayoutGuide
将其高度限制为滚动视图的.frameLayoutGuide
.frameLayoutGuide
将第一个自定义视图的宽度限制为滚动视图的.frameLayoutGuide
的宽度Here is your code, modified with that approach:这是您的代码,使用该方法进行了修改:
class MainVC: UIViewController, UIScrollViewDelegate {
@IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var pageControl: UIPageControl!
var customView1: CustomView1 = CustomView1()
var customView2: CustomView2 = CustomView2()
func setupScrollView() {
pageControl.numberOfPages = 2
// let's put the two custom views in a horizontal stack view
let stack = UIStackView()
stack.axis = .horizontal
stack.distribution = .fillEqually
stack.translatesAutoresizingMaskIntoConstraints = false
stack.addArrangedSubview(customView1)
stack.addArrangedSubview(customView2)
// add the stack view to the scroll view
scrollView.addSubview(stack)
let contentG = scrollView.contentLayoutGuide
let frameG = scrollView.frameLayoutGuide
NSLayoutConstraint.activate([
// constrain stack view to all 4 sides of content layout guide
stack.topAnchor.constraint(equalTo: contentG.topAnchor),
stack.leadingAnchor.constraint(equalTo: contentG.leadingAnchor),
stack.trailingAnchor.constraint(equalTo: contentG.trailingAnchor),
stack.bottomAnchor.constraint(equalTo: contentG.bottomAnchor),
// stack view Height equal to scroll view frame layout guide height
stack.heightAnchor.constraint(equalTo: frameG.heightAnchor),
// stack is set to fillEqually, so we only need to set
// width of first custom view equal to scroll view frame layout guide width
customView1.widthAnchor.constraint(equalTo: frameG.widthAnchor),
])
self.scrollView.delegate = self
}
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
let pageNumber = scrollView.contentOffset.x / scrollView.frame.size.width
pageControl.currentPage = Int(pageNumber)
}
override func viewDidLoad() {
super.viewDidLoad()
setupScrollView()
scrollView.delegate = self
}
}
Edit编辑
Couple additional notes...几个附加说明...
UIScrollView
layout ambiguity. UIScrollView
布局不明确。 As I said in my initial comment, if we add a UIScrollView
in Storyboard / I nterface B uilder, but do NOT give it any constrained content, IB will complain that it has Scrollable Content Size Ambiguity -- because it does .正如我在最初的评论中所说,如果我们在 Storyboard / 接口B uilder 中添加UIScrollView
,但不给它任何受约束的内容,IB 会抱怨它具有可滚动内容大小歧义——因为它确实如此。 We haven't told IB what the content will be.我们还没有告诉 IB 内容是什么。
We can either ignore it, or select the scroll view and, at the bottom of the Size Inspector pane, change Ambiguity
to Never Verify
.我们可以忽略它,或者 select 滚动视图,然后在 Size Inspector 窗格的底部,将Ambiguity
更改为Never Verify
。
As a general rule, you should correct all auto-layout warnings / errors, but in specific cases such as this - where we know that it's setup how we want, and we'll be satisfying constraints at run-time - it doesn't hurt to leave it alone.作为一般规则,您应该更正所有自动布局警告/错误,但在诸如此类的特定情况下 - 我们知道它是按照我们想要的方式设置的,并且我们将在运行时满足约束 - 它不会离开它很痛苦。
UIDatePicker
not being centered horizontally. UIDatePicker
未水平居中。It actually is centered.它实际上是居中的。 If you add this line:如果添加此行:
datePicker.backgroundColor = .green
You'll see that the object frame itself is centered, but the UI elements inside the frame are left-aligned:您会看到 object 框架本身居中,但框架内的 UI 元素是左对齐的:
From quick research, it doesn't appear that can be changed.从快速研究来看,似乎无法改变。
Now, from Apple's docs , we see:现在,从 Apple 的文档中,我们看到:
You should integrate date pickers in your layout using Auto Layout.您应该使用自动布局将日期选择器集成到您的布局中。 Although date pickers can be resized, they should be used at their intrinsic content size.尽管可以调整日期选择器的大小,但它们应该以其固有的内容大小使用。
Curiously, if we add a UIDatePicker
in Storyboard, change its Preferred Style
to Compact
, and give it centerX and centerY constraints... Storyboard doesn't believe it has an intrinsic content size.奇怪的是,如果我们在 Storyboard 中添加一个UIDatePicker
,将其Preferred Style
更改为Compact
,并给它 centerX 和 centerY 约束...... Storyboard 不相信它具有内在的内容大小。
If we add it via code, giving it only X/Y position constraints, it will show up where we want it at its intrinsic content size .如果我们通过代码添加它,只给它 X/Y position 约束,它将以其固有的内容大小显示在我们想要的位置。 But... if we jump into Debug View Hierarchy
, Xcode tells us its Position and size are ambiguous.但是......如果我们跳转到Debug View Hierarchy
, Xcode 告诉我们它的Position 和大小是不明确的。
Now, what's even more fun...现在,更有趣的是……
Tap that control and watch the Debug console fill with 535 Lines of auto-layout errors / warnings!!!点击该控件并观看调试控制台填充535 行自动布局错误/警告!!!
Some quick investigation -- these are all internal auto-layout issues, and have nothing to do with our code or layout.一些快速调查——这些都是内部自动布局问题,与我们的代码或布局无关。
We see similar issues with the iOS built-in keyboard when it starts showing auto-complete options.当 iOS 内置键盘开始显示自动完成选项时,我们会看到类似的问题。
Those are safe to ignore.这些是可以安全忽略的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.