以编程方式将按钮添加到 UIScrollView Swift 5
Add buttons to UIScrollView Swift 5 programmatically
我正在尝试以编程方式在网格中添加一些按钮,其中的行数超过了屏幕大小,因此我希望它们位于 UIScrollView 中。
我的最小工作示例如下:
class ViewController: UIViewController {
//center label and down a bit
let label = UILabel(frame: CGRect(x: UIScreen.main.bounds.width/2 - 100, y: 50, width: 200, height: 200))
// start scroll view underneath label (why not y: 250?)
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 50, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
override func viewDidLoad() {
super.viewDidLoad()
// add label to view
self.view.addSubview(label)
// add Scrollview
self.view.addSubview(scrollView)
// uncommenting the following also doesn't work
//scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: 4000)
// add buttons to scroll view in 5x21 grid
var idx = 1
for row in 0...20 {
for col in 0...4 {
let button = UIButton(frame: CGRect(x: col*50, y: row*50 + 200, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("\(idx)", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
// add button to scroll view
scrollView.addSubview(button)
idx += 1
}
}
}
@objc func buttonAction(sender: UIButton!) {
label.text = sender.title(for: .normal)
}
}
很遗憾,滚动不起作用。即使我明确设置了更大的垂直内容大小(参见注释行)//scrollView.contentSize
我想知道这是否与为固定按钮设置 x 和 y 值有关?但是我还能如何将它们对齐到网格中?
那么,如何在获得工作的 ScrollView 时获得我想要的按钮对齐方式?
我对集合视图做了同样的事情,它是滚动视图的一个子类,在 rows/columns.
方面可以满足您的需要
此外,要管理滚动视图的触摸,您必须为滚动视图实现 UIScrollViewDelegate,特别是要区分触摸和滚动,否则您可能会遇到不可预知的行为。
你真的应该使用自动布局!!!
到目前为止,向滚动视图添加按钮(或任何视图)的最简单方法 - 在您要求的网格布局中 - 并让它自动确定滚动区域是使用堆栈视图。
这是一个简单的例子:
class ViewController: UIViewController {
let label = UILabel()
let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
// start with some text in the label
label.text = "Tap a button"
// center the text in the label
label.textAlignment = .center
// so we can see the frames
label.backgroundColor = .yellow
scrollView.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
// create a vertical stack view to hold the rows of buttons
let verticalStackView = UIStackView()
verticalStackView.axis = .vertical
// we're going to use auto-layout
label.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
// add label to view
self.view.addSubview(label)
// add Scrollview to view
self.view.addSubview(scrollView)
// add stack view to scrollView
scrollView.addSubview(verticalStackView)
// now let's create the buttons and add them
var idx = 1
for row in 0...20 {
// create a "row" stack view
let rowStack = UIStackView()
// add it to the vertical stack view
verticalStackView.addArrangedSubview(rowStack)
for col in 0...4 {
let button = UIButton()
button.backgroundColor = .gray
button.setTitle("\(idx)", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
// add button to row stack view
rowStack.addArrangedSubview(button)
// buttons should be 50x50
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalToConstant: 50.0),
button.heightAnchor.constraint(equalToConstant: 50.0),
])
idx += 1
}
}
// finally, let's set our constraints
// respect safe-area
let safeG = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain label
// 50-pts from top
// 80% of the width
// centered horizontally
label.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 50.0),
label.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 0.8),
label.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
// constrain scrollView
// 50-pts from bottom of label
// Leading and Trailing to safe-area with 8-pts "padding"
// Bottom to safe-area with 8-pts "padding"
scrollView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 50.0),
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -8.0),
// constrain vertical stack view to scrollView Content Layout Guide
// 8-pts all around (so we have a little "padding")
verticalStackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor, constant: 8.0),
verticalStackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor, constant: 8.0),
verticalStackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor, constant: -8.0),
verticalStackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: -8.0),
])
}
@objc func buttonAction(sender: UIButton!) {
label.text = sender.title(for: .normal)
}
}
这是结果:
然后我们将向下滚动并点击另一个按钮:
如果你想要按钮之间的间距,你可以在viewDidLoad()
的末尾添加这样的东西:
// suppose we want 8-pts spacing between the buttons?
verticalStackView.spacing = 8.0
verticalStackView.arrangedSubviews.forEach { v in
if let stack = v as? UIStackView {
stack.spacing = 8.0
}
}
现在看起来像这样:
如果您希望按钮网格水平居中,或者如果您希望调整间距(或按钮大小)以适合,有几种不同的方法可以做到...您没有描述您的最终目标您问题中的目标,但这应该是一个很好的起点。
我正在尝试以编程方式在网格中添加一些按钮,其中的行数超过了屏幕大小,因此我希望它们位于 UIScrollView 中。
我的最小工作示例如下:
class ViewController: UIViewController {
//center label and down a bit
let label = UILabel(frame: CGRect(x: UIScreen.main.bounds.width/2 - 100, y: 50, width: 200, height: 200))
// start scroll view underneath label (why not y: 250?)
let scrollView = UIScrollView(frame: CGRect(x: 0, y: 50, width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
override func viewDidLoad() {
super.viewDidLoad()
// add label to view
self.view.addSubview(label)
// add Scrollview
self.view.addSubview(scrollView)
// uncommenting the following also doesn't work
//scrollView.contentSize = CGSize(width: UIScreen.main.bounds.width, height: 4000)
// add buttons to scroll view in 5x21 grid
var idx = 1
for row in 0...20 {
for col in 0...4 {
let button = UIButton(frame: CGRect(x: col*50, y: row*50 + 200, width: 50, height: 50))
button.backgroundColor = .gray
button.setTitle("\(idx)", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
// add button to scroll view
scrollView.addSubview(button)
idx += 1
}
}
}
@objc func buttonAction(sender: UIButton!) {
label.text = sender.title(for: .normal)
}
}
很遗憾,滚动不起作用。即使我明确设置了更大的垂直内容大小(参见注释行)//scrollView.contentSize
我想知道这是否与为固定按钮设置 x 和 y 值有关?但是我还能如何将它们对齐到网格中?
那么,如何在获得工作的 ScrollView 时获得我想要的按钮对齐方式?
我对集合视图做了同样的事情,它是滚动视图的一个子类,在 rows/columns.
方面可以满足您的需要此外,要管理滚动视图的触摸,您必须为滚动视图实现 UIScrollViewDelegate,特别是要区分触摸和滚动,否则您可能会遇到不可预知的行为。
你真的应该使用自动布局!!!
到目前为止,向滚动视图添加按钮(或任何视图)的最简单方法 - 在您要求的网格布局中 - 并让它自动确定滚动区域是使用堆栈视图。
这是一个简单的例子:
class ViewController: UIViewController {
let label = UILabel()
let scrollView = UIScrollView()
override func viewDidLoad() {
super.viewDidLoad()
// start with some text in the label
label.text = "Tap a button"
// center the text in the label
label.textAlignment = .center
// so we can see the frames
label.backgroundColor = .yellow
scrollView.backgroundColor = UIColor(white: 0.9, alpha: 1.0)
// create a vertical stack view to hold the rows of buttons
let verticalStackView = UIStackView()
verticalStackView.axis = .vertical
// we're going to use auto-layout
label.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
verticalStackView.translatesAutoresizingMaskIntoConstraints = false
// add label to view
self.view.addSubview(label)
// add Scrollview to view
self.view.addSubview(scrollView)
// add stack view to scrollView
scrollView.addSubview(verticalStackView)
// now let's create the buttons and add them
var idx = 1
for row in 0...20 {
// create a "row" stack view
let rowStack = UIStackView()
// add it to the vertical stack view
verticalStackView.addArrangedSubview(rowStack)
for col in 0...4 {
let button = UIButton()
button.backgroundColor = .gray
button.setTitle("\(idx)", for: .normal)
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
// add button to row stack view
rowStack.addArrangedSubview(button)
// buttons should be 50x50
NSLayoutConstraint.activate([
button.widthAnchor.constraint(equalToConstant: 50.0),
button.heightAnchor.constraint(equalToConstant: 50.0),
])
idx += 1
}
}
// finally, let's set our constraints
// respect safe-area
let safeG = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// constrain label
// 50-pts from top
// 80% of the width
// centered horizontally
label.topAnchor.constraint(equalTo: safeG.topAnchor, constant: 50.0),
label.widthAnchor.constraint(equalTo: safeG.widthAnchor, multiplier: 0.8),
label.centerXAnchor.constraint(equalTo: safeG.centerXAnchor),
// constrain scrollView
// 50-pts from bottom of label
// Leading and Trailing to safe-area with 8-pts "padding"
// Bottom to safe-area with 8-pts "padding"
scrollView.topAnchor.constraint(equalTo: label.bottomAnchor, constant: 50.0),
scrollView.leadingAnchor.constraint(equalTo: safeG.leadingAnchor, constant: 8.0),
scrollView.trailingAnchor.constraint(equalTo: safeG.trailingAnchor, constant: -8.0),
scrollView.bottomAnchor.constraint(equalTo: safeG.bottomAnchor, constant: -8.0),
// constrain vertical stack view to scrollView Content Layout Guide
// 8-pts all around (so we have a little "padding")
verticalStackView.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor, constant: 8.0),
verticalStackView.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor, constant: 8.0),
verticalStackView.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor, constant: -8.0),
verticalStackView.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor, constant: -8.0),
])
}
@objc func buttonAction(sender: UIButton!) {
label.text = sender.title(for: .normal)
}
}
这是结果:
然后我们将向下滚动并点击另一个按钮:
如果你想要按钮之间的间距,你可以在viewDidLoad()
的末尾添加这样的东西:
// suppose we want 8-pts spacing between the buttons?
verticalStackView.spacing = 8.0
verticalStackView.arrangedSubviews.forEach { v in
if let stack = v as? UIStackView {
stack.spacing = 8.0
}
}
现在看起来像这样:
如果您希望按钮网格水平居中,或者如果您希望调整间距(或按钮大小)以适合,有几种不同的方法可以做到...您没有描述您的最终目标您问题中的目标,但这应该是一个很好的起点。