Мой Swift 4 UIScrollView с ограничениями авторазметки не прокручивается
Я создал небольшую демонстрационную площадку, чтобы все заработало, прежде чем добавлять представление в мое приложение.
У меня есть представление прокрутки, которое будет содержать несколько кнопок для горизонтальной прокрутки. Я знаю, что эти кнопки должны перейти в представление контейнера в представлении прокрутки и создали это также. Первоначально я использовал ограничения autolayout, чтобы создать все это, но теперь попытался использовать константы, чтобы гарантировать, что представление контента больше, чем представление прокрутки. Однако кнопки все равно не будут прокручиваться... я что-то пропустил? Виды прокрутки не работают с автоматической разметкой?
Я делаю все это программно и на своем iPad, так что решения с построителем интерфейса, к сожалению, не вариант...
Вот полный код:
import UIKit
import PlaygroundSupport
class FilterViewController: UIViewController {
var filterView: UIView!
var scrollView: UIScrollView!
var containerView: UIView!
override func loadView() {
filterView = UIView()
view = filterView
view.backgroundColor = #colorLiteral(red: 0.909803926944733, green: 0.47843137383461, blue: 0.643137276172638, alpha: 1.0)
scrollView = UIScrollView()
scrollView.backgroundColor = #colorLiteral(red: 0.474509805440903, green: 0.839215695858002, blue: 0.976470589637756, alpha: 1.0)
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo:view.topAnchor, constant:40).isActive = true
scrollView.leadingAnchor.constraint(equalTo:view.leadingAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo:view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalToConstant: 200).isActive = true
scrollView.isScrollEnabled = true
containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
scrollView.addSubview(containerView)
containerView.frame = CGRect(x: 0, y: 0, width: 1080, height: 200)
}
class Buttons{
let button = UIButton()
init (titleText : String){
button.backgroundColor = #colorLiteral(red: 0.976470589637756, green: 0.850980401039124, blue: 0.549019634723663, alpha: 1.0)
button.setTitle(titleText, for: .normal)
button.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let b1 = Buttons(titleText: "one")
let b2 = Buttons(titleText: "two")
let b3 = Buttons(titleText: "three")
let b4 = Buttons(titleText: "four")
let b5 = Buttons(titleText: "five")
let buttonArray = [b1,b2,b3,b4,b5]
var startPoint : CGFloat = 0.0
for btn in buttonArray {
let theBtn = btn.button
containerView.addSubview(theBtn)
theBtn.frame = CGRect(x: startPoint, y: 0, width: 200, height: 200)
startPoint += 220
}
}
}
let filterViewController = FilterViewController()
PlaygroundPage.current.liveView = filterViewController
Спасибо ВАВАВАМА! Вот полный (работающий сейчас) мини-проект со всеми ограничениями автоматической компоновки:
import UIKit
import PlaygroundSupport
class FilterViewController: UIViewController {
var filterView: UIView!
var scrollView: UIScrollView!
var containerView: UIView!
override func loadView() {
filterView = UIView()
view = filterView
view.backgroundColor = #colorLiteral(red: 0.909803926944733, green: 0.47843137383461, blue: 0.643137276172638, alpha: 1.0)
scrollView = UIScrollView()
scrollView.backgroundColor = #colorLiteral(red: 0.474509805440903, green: 0.839215695858002, blue: 0.976470589637756, alpha: 1.0)
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo:view.topAnchor, constant:40).isActive = true
scrollView.leadingAnchor.constraint(equalTo:view.leadingAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo:view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.25).isActive = true
scrollView.isScrollEnabled = true
containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
scrollView.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.topAnchor.constraint(equalTo:scrollView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo:scrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo:scrollView.bottomAnchor).isActive = true
containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
}
class Buttons{
let button = UIButton()
init (titleText : String){
button.backgroundColor = #colorLiteral(red: 0.976470589637756, green: 0.850980401039124, blue: 0.549019634723663, alpha: 1.0)
button.setTitle(titleText, for: .normal)
//button.frame = CGRect(x: 0, y: 0, width: 200, height: 200)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let b1 = Buttons(titleText: "one")
let b2 = Buttons(titleText: "two")
let b3 = Buttons(titleText: "three")
let b4 = Buttons(titleText: "four")
let b5 = Buttons(titleText: "five")
let buttonArray = [b1,b2,b3,b4,b5]
var startPoint = containerView.leadingAnchor
for btn in buttonArray {
let theBtn = btn.button
containerView.addSubview(theBtn)
theBtn.translatesAutoresizingMaskIntoConstraints = false
theBtn.leadingAnchor.constraint(equalTo:startPoint, constant:20).isActive = true
theBtn.topAnchor.constraint(equalTo:containerView.topAnchor).isActive = true
theBtn.bottomAnchor.constraint(equalTo:containerView.bottomAnchor).isActive = true
theBtn.widthAnchor.constraint(equalTo: theBtn.heightAnchor).isActive = true
startPoint = theBtn.trailingAnchor
containerView.widthAnchor.constraint(equalTo: theBtn.widthAnchor, multiplier:CGFloat(buttonArray.count), constant: CGFloat(buttonArray.count * 20)).isActive = true
}
}
}
let filterViewController = FilterViewController()
PlaygroundPage.current.liveView = filterViewController
1 ответ
Вы можете сделать это с помощью Auto Layout. Секрет в том, чтобы ограничить края containerView
к краям scrollView
, Это не интуитивно понятно, но ограничивает края containerView
не устанавливает размер, он просто гарантирует, что размер содержимого scrollView
растет как containerView
растет. Устанавливая ограничения для ширины containerView
к константе, которая является большим числом, чем ширина scrollView
, контент будет прокручиваться горизонтально.
Примечание: при настройке scrollView
таким образом, вы не установите contentSize
из scrollView
, contentSize
будет рассчитан для вас Auto Layout и будет равен размеру containerView
, Важно убедиться, что размер containerView
полностью определяется ограничениями.
Вот что я изменил, чтобы заставить это работать:
containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
scrollView.addSubview(containerView)
//containerView.frame = CGRect(x: 0, y: 0, width: 1080, height: 200)
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.topAnchor.constraint(equalTo:scrollView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo:scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo:scrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo:scrollView.bottomAnchor).isActive = true
containerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
containerView.widthAnchor.constraint(equalToConstant: 1080).isActive = true
Почему мой контент не прокручивается?
Для прокрутки containerView
должен быть больше чем scrollView
, Ваша ошибка в том, что вы установили ограничения таким образом, чтобы containerView
такой же ширины и высоты, как scrollView
и именно поэтому ваш контент не прокручивается.
Если вы хотите прокрутить горизонтально, ширина containerView
должен быть больше чем scrollView
ширина Вы можете сделать это одним из двух способов:
Укажите явную постоянную ширину для
containerView
это больше, чемscrollView
ширинаИЛИ ЖЕ
Цепочка подпредставлений
containerView
слева направо, причем крайний левый элемент находится на переднем краеcontainerView
, Полностью укажите ширину подпредставлений и поместите ограничения по расстоянию между подпредставлениями. Крайнее правое подпредставление должно иметь смещение от задней кромкиcontainerView
, Делая это, Auto Layout может вычислить ширинуcontainerView
и установитьcontentSize
изscrollView
,
Мини проект: обновление
Это версия вашего мини-проекта, которая использует цепочку ограниченных представлений для определения containerView
ширина Ключ является последним ограничением после for
зациклиться viewDidLoad()
который соединяет трейлинг-якорь последней кнопки (он же startPoint
) к containerView
Завязываю якорь. Это завершает цепочку противопоказаний и кнопок, которые соединяют передний край containerView
с задней кромкой containerView
, При этом Auto Layout может вычислить ширину containerView
и установить contentSize
из scrollView
,
import UIKit
import PlaygroundSupport
class FilterViewController: UIViewController {
var filterView: UIView!
var scrollView: UIScrollView!
var containerView: UIView!
override func loadView() {
filterView = UIView()
view = filterView
view.backgroundColor = #colorLiteral(red: 0.909803926944733, green: 0.47843137383461, blue: 0.643137276172638, alpha: 1.0)
scrollView = UIScrollView()
scrollView.backgroundColor = #colorLiteral(red: 0.474509805440903, green: 0.839215695858002, blue: 0.976470589637756, alpha: 1.0)
view.addSubview(scrollView)
scrollView.translatesAutoresizingMaskIntoConstraints = false
scrollView.topAnchor.constraint(equalTo: view.topAnchor, constant: 40).isActive = true
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
scrollView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
scrollView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.25).isActive = true
scrollView.isScrollEnabled = true
containerView = UIView()
containerView.backgroundColor = #colorLiteral(red: 0.176470592617989, green: 0.498039215803146, blue: 0.756862759590149, alpha: 1.0)
scrollView.addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
// This is key: connect all four edges of the containerView to
// to the edges of the scrollView
containerView.topAnchor.constraint(equalTo: scrollView.topAnchor).isActive = true
containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor).isActive = true
containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor).isActive = true
containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor).isActive = true
// Making containerView and scrollView the same height means the
// content will not scroll vertically
containerView.heightAnchor.constraint(equalTo: scrollView.heightAnchor).isActive = true
}
class Buttons {
let button = UIButton()
init(titleText: String) {
button.backgroundColor = #colorLiteral(red: 0.976470589637756, green: 0.850980401039124, blue: 0.549019634723663, alpha: 1.0)
button.setTitle(titleText, for: .normal)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let b1 = Buttons(titleText: "one")
let b2 = Buttons(titleText: "two")
let b3 = Buttons(titleText: "three")
let b4 = Buttons(titleText: "four")
let b5 = Buttons(titleText: "five")
let buttonArray = [b1, b2, b3, b4, b5]
var startPoint = containerView.leadingAnchor
for btn in buttonArray {
let theBtn = btn.button
containerView.addSubview(theBtn)
theBtn.translatesAutoresizingMaskIntoConstraints = false
theBtn.leadingAnchor.constraint(equalTo: startPoint, constant: 20).isActive = true
theBtn.topAnchor.constraint(equalTo: containerView.topAnchor).isActive = true
theBtn.bottomAnchor.constraint(equalTo: containerView.bottomAnchor).isActive = true
theBtn.widthAnchor.constraint(equalTo: theBtn.heightAnchor).isActive = true
startPoint = theBtn.trailingAnchor
}
// Complete the chain of constraints
containerView.trailingAnchor.constraint(equalTo: startPoint, constant: 20).isActive = true
}
}
let filterViewController = FilterViewController()
PlaygroundPage.current.liveView = filterViewController