如何将 UICollectionReusableView 拉伸到安全区域
How to UICollectionReusableView stretch to Safe Area
我正在尝试在我的 UICollectionView class 中显示 HeaderView,为此我使用 UICollectionReusableView class。
实际上我在我的 CollectionView 中显示了 HeaderView 但它没有到达安全区域。
我以编程方式使用自动布局,并为此编写了扩展程序。
这是我的 class 和我在代码中使用的扩展:
import Foundation
import UIKit
private let headerIdentifer = "HeaderCell"
class ProfileController: UICollectionViewController {
//MARK: - Properties
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureProfileCollectionView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.isHidden = true
}
//MARK: - Helpers
func configureProfileCollectionView() {
collectionView.backgroundColor = .white
collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifer)
}
}
extension ProfileController {
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifer, for: indexPath) as! HeaderView
return header
}
}
extension ProfileController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 300)
}
}
import Foundation
import UIKit
class HeaderView: UICollectionReusableView {
//MARK: - Properties
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = .systemBlue
view.addSubview(backButton)
backButton.anchor(top: view.topAnchor, left: view.leftAnchor,
paddingTop: 42, paddingLeft: 16)
backButton.setDimensions(width: 30, height: 30)
return view
}()
private lazy var backButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(named: "baseline_arrow_back_white_24dp")?.withRenderingMode(.alwaysOriginal), for: .normal)
button.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
return button
}()
//MARK: - Lifecyle
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(containerView)
containerView.anchor(top: topAnchor, left: leftAnchor, right: rightAnchor, height: 108)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Selectors
@objc func backButtonTapped() {
}
}
import UIKit
extension UIView {
func anchor(top: NSLayoutYAxisAnchor? = nil,
left: NSLayoutXAxisAnchor? = nil,
bottom: NSLayoutYAxisAnchor? = nil,
right: NSLayoutXAxisAnchor? = nil,
paddingTop: CGFloat = 0,
paddingLeft: CGFloat = 0,
paddingBottom: CGFloat = 0,
paddingRight: CGFloat = 0,
width: CGFloat? = nil,
height: CGFloat? = nil) {
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let left = left {
leftAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
}
if let right = right {
rightAnchor.constraint(equalTo: right, constant: -paddingRight).isActive = true
}
if let width = width {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if let height = height {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
func center(inView view: UIView, yConstant: CGFloat? = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: yConstant!).isActive = true
}
func centerX(inView view: UIView, topAnchor: NSLayoutYAxisAnchor? = nil, paddingTop: CGFloat? = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
if let topAnchor = topAnchor {
self.topAnchor.constraint(equalTo: topAnchor, constant: paddingTop!).isActive = true
}
}
func centerY(inView view: UIView, leftAnchor: NSLayoutXAxisAnchor? = nil, paddingLeft: CGFloat? = nil, constant: CGFloat? = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: constant!).isActive = true
if let leftAnchor = leftAnchor, let padding = paddingLeft {
self.leftAnchor.constraint(equalTo: leftAnchor, constant: padding).isActive = true
}
}
func setDimensions(width: CGFloat, height: CGFloat) {
translatesAutoresizingMaskIntoConstraints = false
widthAnchor.constraint(equalToConstant: width).isActive = true
heightAnchor.constraint(equalToConstant: height).isActive = true
}
func addConstraintsToFillView(_ view: UIView) {
translatesAutoresizingMaskIntoConstraints = false
anchor(top: view.topAnchor, left: view.leftAnchor,
bottom: view.bottomAnchor, right: view.rightAnchor)
}
}
我相信 UICollectionReusableView
设置得很好,并且我认为由于安全区域的缘故,自动插入应用于 UICollectionView
。
在您的viewDidLoad
中尝试以下两个选项之一,它可能会起作用
// Option 1
// Get the inset applied at the top and negate the applied inset
if let top
= UIApplication.shared.windows.first?.safeAreaInsets.top
{
collectionView.contentInset.top = -top
}
// Option 2
// Request the collection view to ignore the default behavior
// to add an inset for safe area
collectionView.contentInsetAdjustmentBehavior = .never
更简单的解决方案。无需编写任何代码!!!
我正在尝试在我的 UICollectionView class 中显示 HeaderView,为此我使用 UICollectionReusableView class。
实际上我在我的 CollectionView 中显示了 HeaderView 但它没有到达安全区域。
我以编程方式使用自动布局,并为此编写了扩展程序。
这是我的 class 和我在代码中使用的扩展:
import Foundation
import UIKit
private let headerIdentifer = "HeaderCell"
class ProfileController: UICollectionViewController {
//MARK: - Properties
//MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
configureProfileCollectionView()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationController?.navigationBar.isHidden = true
}
//MARK: - Helpers
func configureProfileCollectionView() {
collectionView.backgroundColor = .white
collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerIdentifer)
}
}
extension ProfileController {
override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerIdentifer, for: indexPath) as! HeaderView
return header
}
}
extension ProfileController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
return CGSize(width: view.frame.width, height: 300)
}
}
import Foundation
import UIKit
class HeaderView: UICollectionReusableView {
//MARK: - Properties
private lazy var containerView: UIView = {
let view = UIView()
view.backgroundColor = .systemBlue
view.addSubview(backButton)
backButton.anchor(top: view.topAnchor, left: view.leftAnchor,
paddingTop: 42, paddingLeft: 16)
backButton.setDimensions(width: 30, height: 30)
return view
}()
private lazy var backButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(UIImage(named: "baseline_arrow_back_white_24dp")?.withRenderingMode(.alwaysOriginal), for: .normal)
button.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside)
return button
}()
//MARK: - Lifecyle
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(containerView)
containerView.anchor(top: topAnchor, left: leftAnchor, right: rightAnchor, height: 108)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//MARK: - Selectors
@objc func backButtonTapped() {
}
}
import UIKit
extension UIView {
func anchor(top: NSLayoutYAxisAnchor? = nil,
left: NSLayoutXAxisAnchor? = nil,
bottom: NSLayoutYAxisAnchor? = nil,
right: NSLayoutXAxisAnchor? = nil,
paddingTop: CGFloat = 0,
paddingLeft: CGFloat = 0,
paddingBottom: CGFloat = 0,
paddingRight: CGFloat = 0,
width: CGFloat? = nil,
height: CGFloat? = nil) {
translatesAutoresizingMaskIntoConstraints = false
if let top = top {
topAnchor.constraint(equalTo: top, constant: paddingTop).isActive = true
}
if let left = left {
leftAnchor.constraint(equalTo: left, constant: paddingLeft).isActive = true
}
if let bottom = bottom {
bottomAnchor.constraint(equalTo: bottom, constant: -paddingBottom).isActive = true
}
if let right = right {
rightAnchor.constraint(equalTo: right, constant: -paddingRight).isActive = true
}
if let width = width {
widthAnchor.constraint(equalToConstant: width).isActive = true
}
if let height = height {
heightAnchor.constraint(equalToConstant: height).isActive = true
}
}
func center(inView view: UIView, yConstant: CGFloat? = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: yConstant!).isActive = true
}
func centerX(inView view: UIView, topAnchor: NSLayoutYAxisAnchor? = nil, paddingTop: CGFloat? = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
if let topAnchor = topAnchor {
self.topAnchor.constraint(equalTo: topAnchor, constant: paddingTop!).isActive = true
}
}
func centerY(inView view: UIView, leftAnchor: NSLayoutXAxisAnchor? = nil, paddingLeft: CGFloat? = nil, constant: CGFloat? = 0) {
translatesAutoresizingMaskIntoConstraints = false
centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: constant!).isActive = true
if let leftAnchor = leftAnchor, let padding = paddingLeft {
self.leftAnchor.constraint(equalTo: leftAnchor, constant: padding).isActive = true
}
}
func setDimensions(width: CGFloat, height: CGFloat) {
translatesAutoresizingMaskIntoConstraints = false
widthAnchor.constraint(equalToConstant: width).isActive = true
heightAnchor.constraint(equalToConstant: height).isActive = true
}
func addConstraintsToFillView(_ view: UIView) {
translatesAutoresizingMaskIntoConstraints = false
anchor(top: view.topAnchor, left: view.leftAnchor,
bottom: view.bottomAnchor, right: view.rightAnchor)
}
}
我相信 UICollectionReusableView
设置得很好,并且我认为由于安全区域的缘故,自动插入应用于 UICollectionView
。
在您的viewDidLoad
中尝试以下两个选项之一,它可能会起作用
// Option 1
// Get the inset applied at the top and negate the applied inset
if let top
= UIApplication.shared.windows.first?.safeAreaInsets.top
{
collectionView.contentInset.top = -top
}
// Option 2
// Request the collection view to ignore the default behavior
// to add an inset for safe area
collectionView.contentInsetAdjustmentBehavior = .never
更简单的解决方案。无需编写任何代码!!!