Как сделать так, чтобы три View делили экран ровно на три части?
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Распределение экрана на три равные части между UIView
Существует несколько подходов к равномерному распределению трех UIView по высоте или ширине экрана (или родительского контейнера). Основные методы реализуются через:
- Auto Layout (современный, рекомендуемый способ)
- Frame-based layout (математический расчет)
- UIStackView (самый простой вариант для равномерного распределения)
1. Использование UIStackView (наиболее простой метод)
UIStackView автоматически управляет распределением своих subviews согласно заданным параметрам.
import UIKit
class ThreeEqualPartsViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Создаем три view с разными цветами для визуализации
let redView = UIView()
redView.backgroundColor = .red
let greenView = UIView()
greenView.backgroundColor = .green
let blueView = UIView()
blueView.backgroundColor = .blue
// Создаем вертикальный stack view
let stackView = UIStackView(arrangedSubviews: [redView, greenView, blueView])
stackView.axis = .vertical // Распределение по вертикали
stackView.distribution = .fillEqually // Ключевой параметр: равное заполнение
stackView.alignment = .fill
stackView.spacing = 0 // Убираем промежутки между view
// Добавляем stack view на главный view и устанавливаем constraints
view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: view.topAnchor),
stackView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
stackView.leftAnchor.constraint(equalTo: view.leftAnchor),
stackView.rightAnchor.constraint(equalTo: view.rightAnchor)
])
}
}
Примечание: Для горизонтального распределения измените axis на .horizontal. Этот метод гарантирует точное равенство частей независимо от размеров экрана.
2. Использование Auto Layout с Constraints (без UIStackView)
Можно создать равные части путем установки прямых constraints между views.
import UIKit
class ThreeEqualPartsConstraintViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let view1 = UIView()
view1.backgroundColor = .red
let view2 = UIView()
view2.backgroundColor = .green
let view3 = UIView()
view3.backgroundColor = .blue
view.addSubview(view1)
view.addSubview(view2)
view.addSubview(view3)
// Отключаем авто конвертацию масок в constraints
[view1, view2, view3].forEach { $0.translatesAutoresizingMaskIntoConstraints = false }
// Вертикальное распределение: фиксируем верх и низ, связываем соседние view
NSLayoutConstraint.activate([
// Первое view: сверху к родителю, высота равна второму view
view1.topAnchor.constraint(equalTo: view.topAnchor),
view1.leftAnchor.constraint(equalTo: view.leftAnchor),
view1.rightAnchor.constraint(equalTo: view.rightAnchor),
view1.heightAnchor.constraint(equalTo: view2.heightAnchor),
// Второе view: сверху к первому view, высота равна третьему view
view2.topAnchor.constraint(equalTo: view1.bottomAnchor),
view2.leftAnchor.constraint(equalTo: view.leftAnchor),
view2.rightAnchor.constraint(equalTo: view.rightAnchor),
view2.heightAnchor.constraint(equalTo: view3.heightAnchor),
// Третье view: сверху к второму view, низ к родителю
view3.topAnchor.constraint(equalTo: view2.bottomAnchor),
view3.leftAnchor.constraint(equalTo: view.leftAnchor),
view3.rightAnchor.constraint(equalTo: view.rightAnchor),
view3.bottomAnchor.constraint(equalTo: view.bottomAnchor)
])
}
}
Ключевой момент: Мы связали высоты view1.heightAnchor == view2.heightAnchor и view2.heightAnchor == view3.heightAnchor, что создает транзитивное равенство всех трех высот. Последнее view также прикреплено к bottomAnchor родителя, что фиксирует общую высоту.
3. Frame-based layout (для ручного расчета)
Это исторический подход, который менее гибкий, но может использоваться в специфических контекстах (например, в drawRect).
import UIKit
class ThreeEqualPartsFrameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let totalHeight = view.bounds.height
let partHeight = totalHeight / 3
let view1 = UIView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: partHeight))
view1.backgroundColor = .red
let view2 = UIView(frame: CGRect(x: 0, y: partHeight, width: view.bounds.width, height: partHeight))
view2.backgroundColor = .green
let view3 = UIView(frame: CGRect(x: 0, y: partHeight * 2, width: view.bounds.width, height: partHeight))
view3.backgroundColor = .blue
view.addSubview(view1)
view.addSubview(view2)
view.addSubview(view3)
}
// Важно: пересчитать frames при изменении размеров (например, ротация)
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
let totalHeight = view.bounds.height
let partHeight = totalHeight / 3
view.subviews[0].frame = CGRect(x: 0, y: 0, width: view.bounds.width, height: partHeight)
view.subviews[1].frame = CGRect(x: 0, y: partHeight, width: view.bounds.width, height: partHeight)
view.subviews[2].frame = CGRect(x: 0, y: partHeight * 2, width: view.bounds.width, height: partHeight)
}
}
Критические рекомендации
- UIStackView — предпочтительный метод для современных приложений: минимальный код, автоматическая адаптация, поддержка Dynamic Type и изменений ориентации.
- При использовании Auto Layout напрямую важно убедиться, что все translatesAutoresizingMaskIntoConstraints установлены в
false. - Для сложных сценариев (например, разные пропорции в портретной и landscape ориентации) можно комбинировать подходы или использовать UILayoutGuide как промежуточные анкеры.
- Всегда учитывайте safe area insets на устройствах с "челкой": вместо
view.topAnchorиспользуйтеview.safeAreaLayoutGuide.topAnchor.
Выбор метода зависит от контекста: для статических интерфейсов подойдет UIStackView, для динамических изменений — прямые constraints, для кастомной анимации или рисования — frame-based расчет с обновлением в viewWillLayoutSubviews.