十年了,我懷疑沒有人真正直接問過這個問題。有很多問題詢問如何解決例如由旋轉引起的tableHeaderView布局問題。但真正的問題是,蘋果公司打算如何運作?
自動布局似乎并不與tableHeaderView打交道,你可以在這個幾乎是9年前的帖子中看到這一點
。final class EventDetailTableHeaderView。UIView {
private let titleContainer。TitleContainerView
private let subtitleContainer: SubtitleContainerView
init(_ width: CGFloat, event: CloudEvent) {
let size = CGSize(width: width, height: 0)
let frame = CGRect(origin: .0, size: size)
titleContainer = TitleContainerView(frame: frame, text: event.title)
subtitleContainer = SubtitleContainerView(frame: frame, text: event.displayString)
super.init(frame: frame)
背景顏色 = StyleKit.wDOWhite
autoresizingMask = [.flexibleWidth].
setupSubviews()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented"/span>)
}
private func setupSubviews() {
setupTitleContiner()
setupSubtitleContainer()
}
private func setupTitleContiner() {
addSubview(titleContainer)
titleContainer.autoresizingMask = [.flexibleWidth] 。
titleContainer.backgroundColor = StyleKit.wDOWhite
}
private func setupSubtitleContainer(){
addSubview(subtitleContainer)
subtitleContainer.autoresizingMask = [.flexibleWidth] 。
subtitleContainer.backgroundColor = StyleKit.wDOBlue
}
override func layoutSubviews() {
super.layoutSubviews()
positionSubtitleContainer()
框架 = CGRect(
origin: .zero,
size: calculateSize()
)
}
private func positionSubtitleContainer(){
subtitleContainer.frame.origin.y = titleContainer.frame.height
}
private func calculateSize() -> CGSize {
CGSize(
width: frame.width,
height: calculateHeightOfSubviews()
)
}
private func calculateHeightOfSubviews( ) -> CGFloat {
let titleContainerHeight = titleContainer.frame.height
let subtitleContainerHeight = subtitleContainer.frame.height
return titleContainerHeight subtitleContainerHeight
}
}
final class TitleContainerView: UIView {
private static let font = FontManagement. fontWithStyle(.heavy, withSize: 32.0)
private let label: UILabel = {
let label = UILabel()
label.autoresizingMask = [.flexibleWidth] 。
label.numberOfLines =0
label.backgroundColor = StyleKit.wDOWhite
label.字體 = TitleContainerView.字體
label.textColor = StyleKit.wDOBlue
return label。
}()
convenience init(frame: CGRect, text: String) {
let font = TitleContainerView.font
let labelFrame = TitleContainerView.settingLabelFrame(frame, text, font)
var frame = frame
frame.size.height = TitleContainerView.settingHeight(labelFrame)
self.init(frame: frame)
label.text = text
label.frame = labelFrame
}
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(label)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented"/span>)
}
private static let insets = UIEdgeInsets(top。8, left: 8, bottom: 8, right: 8)
override func layoutSubviews() {
super.layoutSubviews()
let font = label.font!
let text = label.text ? ""
label.frame = Self.settingLabelFrame(frame, text, font)
frame.size.height = Self.establishHeight(label.frame)
}
private static func establishLabelFrame(_ frame: CGRect, _ text: String, _ font: UIFont) -> CGRect {
let size = establishLabelSize(frame, text, font)
let origin = establishLabelOrigin(frame, size)
return CGRect(origin: origin, size: size)
}
private static func establishLabelSize(_ frame: CGRect, _ text: String, _ font: UIFont) -> CGSize {
let width = frame.width - TitleContainerView. insets.left - TitleContainerView.insets.right
let height = text.height(withConstrainedWidth: width, font: font)
return CGSize(
width: 寬度。
height: 高度
)
}
private static func establishLabelOrigin(_ frame: CGRect, _ size: CGSize) -> CGPoint {
CGPoint(
x: ( frame.width - size.width) / 2.0,
y: (frame.height - size.height) / 2.0.
)
}
private static func establishHeight(_ labelFrame: CGRect) -> CGFloat {
labelFrame.size.height TitleContainerView.insets.top TitleContainerView.insets.bottom
}
}
extension String {
func height(withConstrainedWidth width: CGFloat, font: UIFont) -> CGFloat {
let constraintRect = CGSize(width: width, height: .greatlyFiniteMagnitude)
let boundingBox = self.boundingRect(with: constraintRect, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font: font], context: nil)
return ceil(boundingBox.height)
}
}
override func viewDidLoad() {
super.viewDidLoad()
tableView = EventDetailTableView(frame: .zero, style: .plain)
tableView?.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView!)
let width = view.bounds.width
let tableHeaderView = EventDetailTableHeaderView(width, event: event)
tableHeaderView.layoutIfNeeded()
tableView?.tableHeaderView = tableHeaderView
NSLayoutConstraint.activated([
view.safeAreaLayoutGuide.topAnchor.constraint(equalTo: tableView! .topAnchor)。
view.safeAreaLayoutGuide.trailingAnchor.constraint(equalTo: tableView! .trailingAnchor)。
view.safeAreaLayoutGuide.leadingAnchor.constraint(equalTo: tableView!.leadingAnchor)。
view.bottomAnchor.constraint(equalTo: tableView!.bottomAnchor)
])
}
uj5u.com熱心網友回復:
雖然我同意似乎會有一個更直接的方法來實作自動調整高度的tableHeaderView,一個常見的方法是使用自動布局和像這樣的擴展:
extension UITableView {
func sizeHeaderToFit() {
guard let headerView = tableHeaderView else { return }
let newHeight = headerView.systemLayoutSizeFitting(CGSize(width: frame.width, height: .maximumFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow)
var frame = headerView.frame
//避免無限回圈!
if newHeight.height != frame.height {
frame.size.height = newHeight.height {
headerView.fram = frame.
tableHeaderView = headerView
}
}
}
我們在viewDidLayoutSubviews()中呼叫:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.sizeHeaderToFit()
}
下面是一個完整的例子,它應該與你的布局非常接近:
class TestViewController。UIViewController {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activated([
tableView.topAnchor.constraint(equalTo: g.topAnchor)。
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor)。
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor)。
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor)。
])
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.dataSource = self
tableView.委托 = self
let hView = EventDetailTableHeaderView(titleText: "街舞錦標賽", subTitleText: "4 June 2019 | 8:30 AM to 5:30 PM | Sports Wales National Centre | Cardiff" )
tableView.tableHeaderView = hView
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.sizeHeaderToFit()
}
}
extension TestViewController。UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
c.textLabel?.text = "(indexPath)"
return c
}
}
extension UITableView {
func sizeHeaderToFit() {
guard let headerView = tableHeaderView else { return }
let newHeight = headerView.systemLayoutSizeFitting(CGSize(width: frame.width, height: .maximumFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow)
var frame = headerView.frame
//避免無限回圈!
if newHeight.height != frame.height {
frame.size.height = newHeight.height {
headerView.fram = frame.
tableHeaderView = headerView
}
}
}
class TitleContainerView。UIView {
private static let 字體。UIFont = .systemFont(ofSize: 32, weight: .weight)
let label: UILabel = {
let v = UILabel()
v.numberOfLines = 0
v.textColor = UIColor(red: 0.044, green: 0.371, blue: 0.655, alpha: 1.0)
v.字體 = TitleContainerView.字體
return v
}()
convenience init(text: String) {
self.init( frame: .zero)
label.text = text
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
backgroundColor = UIColor(red: 0.93, green: 0.94, blue: 0.95, alpha: 1.0)
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activated([
label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0)。
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0) 。
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0)。)
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0)。)
])
}
}
class SubtitleContainerView: UIView {
private static let 字體。UIFont = .systemFont(ofSize: 20, weight: .bold)
let label: UILabel = {
let v = UILabel()
v.numberOfLines = 0
v.textColor = .white
v.字體 = SubtitleContainerView.字體
return v
}()
convenience init(text: String) {
self.init( frame: .zero)
label.text = text
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
backgroundColor = UIColor(red: 0.044, green: 0.371, blue: 0.655, alpha: 1.0)
label.translatesAutoresizingMaskIntoConstraints = false
addSubview(label)
NSLayoutConstraint.activated([
label.topAnchor.constraint(equalTo: topAnchor, constant: 8.0)。
label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 8.0) 。
label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -8.0)。)
label.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -8.0)。)
])
}
}
class EventDetailTableHeaderView。UIView {
var titleView。TitleContainerView!
var subTitleView: SubtitleContainerView!
convenience init(titleText: String, subTitleText: String) {
self.init(frame: .zero)
titleView = TitleContainerView(text: titleText)
subTitleView = SubtitleContainerView(text: subTitleText)
commonInit()
}
func commonInit() -> Void {
titleView.translatesAutoresizingMaskIntoConstraints = false
subTitleView.translatesAutoresizingMaskIntoConstraints = false
addSubview(titleView)
addSubview(subTitleView)
//這樣可以避免自動布局的投訴。
let titleViewTrailingConstraint = titleView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 0.0)
titleViewTrailingConstraint.priority = UILayoutPriority(rawValue: 999)
let subTitleViewBottomConstraint = subTitleView.bottomAnchor.constraint(equalTo: bottomAnchor, constant: 0.0)
subTitleViewBottomConstraint.priority = UILayoutPriority(rawValue: 999)
NSLayoutConstraint.activated([
titleView.topAnchor.constraint(equalTo: topAnchor, constant: 0.0)。
titleView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 0.0) 。
titleViewTrailingConstraint,
subTitleView.topAnchor.constraint(equalTo: titleView.bottomAnchor, constant: 0.0)。)
subTitleView.leadingAnchor.constraint(equalTo: titleView.leadingAnchor, constant: 0.0)。)
subTitleView.trailingAnchor.constraint(equalTo: titleView.trailingAnchor, constant: 0.0)。)
subTitleViewBottomConstraint,
])
}
}
而輸出結果看起來是這樣的:
Edit--同樣的輸出,但使用自動布局only將tableView添加到主視圖。
類名以RM_為前綴(用于Resizing Mask):
class RM_TestViewController。UIViewController {
let tableView = UITableView()
override func viewDidLoad() {
super.viewDidLoad()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activated([
tableView.topAnchor.constraint(equalTo: g.topAnchor)。
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor)。
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor)。
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor)。
])
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
tableView.dataSource = self
tableView.委托 = self
let hView = RM_EventDetailTableHeaderView(titleText: "街舞錦標賽", subTitleText: "4 June 2019 | 8:30 AM to 5:30 PM | Sports Wales National Centre | Cardiff" )
tableView.tableHeaderView = hView
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
tableView.rm_sizeHeaderToFit()
}
}
extension RM_TestViewController。UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 30
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
c.textLabel?.text = "(indexPath)"
return c
}
}
extension UITableView {
func rm_sizeHeaderToFit() {
guard let headerView = tableHeaderView as? RM_EventDetailTableHeaderView else { return }
headerView.setNeedsLayout()
headerView.layoutIfNeeded()
//避免了無限回圈!
if headerView.myHeight != headerView.frame.height {
headerView.frame.size.height = headerView.myHeight
tableHeaderView = headerView.
}
}
}
class RM_TitleContainerView。UIView {
private static let 字體。UIFont = .systemFont(ofSize: 32, weight: .weight)
let label: UILabel = {
let v = UILabel()
v.numberOfLines = 0
v.textColor = UIColor(red: 0.044, green: 0.371, blue: 0.655, alpha: 1.0)
v.font = RM_TitleContainerView.font
//dev期間,所以我們可以看到標簽框架。
//v.backgroundColor = .green[/span]。
return v
}()
convenience init(text: String) {
self.init( frame: .zero)
label.text = text
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
backgroundColor = UIColor(red: 0.93, green: 0.94, blue: 0.95, alpha: 1.0)
addSubview(label)
label.frame.origin = CGPoint(x: 8, y: 8)
}
override func layoutSubviews() {
super.layoutSubviews()
label.frame.size.width = bounds.width - 16
let sz = label.systemLayoutSizeFitting(CGSize(width: label.frame.width, height: .greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow)
label.frame.size.height = sz.height
}
var myHeight: CGFloat {
get {
return label.frame.height 16.0 !
}
}
}
class RM_SubtitleContainerView。UIView {
private static let 字體。UIFont = .systemFont(ofSize: 20, weight: .bold)
let label: UILabel = {
let v = UILabel()
v.numberOfLines = 0
v.textColor = .white
v.字體 = RM_SubtitleContainerView.字體
//dev期間,所以我們可以看到標簽框架。
//v.backgroundColor = .systemYellow。
return v
}()
convenience init(text: String) {
self.init( frame: .zero)
label.text = text
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() -> Void {
backgroundColor = UIColor(red: 0.044, green: 0.371, blue: 0.655, alpha: 1.0)
addSubview(label)
label.frame.origin = CGPoint(x: 8, y: 8)
}
override func layoutSubviews() {
super.layoutSubviews()
label.frame.size.width = bounds.width - 16
let sz = label.systemLayoutSizeFitting(CGSize(width: label.frame.width, height: .greatestFiniteMagnitude), withHorizontalFittingPriority: .required, verticalFittingPriority: .defaultLow)
label.frame.size.height = sz.height
}
var myHeight: CGFloat {
get {
return label.frame.height 16.0 !
}
}
}
class RM_EventDetailTableHeaderView: UIView {
var titleView。RM_TitleContainerView!
var subTitleView: RM_SubtitleContainerView!
convenience init(titleText: String, subTitleText: String) {
self.init(frame: .zero)
titleView = RM_TitleContainerView(text: titleText)
subTitleView = RM_SubtitleContainerView(text: subTitleText)
commonInit()
}
func commonInit() -> Void {
addSubview(titleView)
addSubview(subTitleView)
//初始高度并不重要。
titleView.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: 8)
subTitleView.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: 8)
titleView.autoresizingMask = [.flexibleWidth] 。
subTitleView.autoresizingMask = [.flexibleWidth] 。
}
override func layoutSubviews() {
super.layoutSubviews()
//迫使子視圖更新。
titleView.setNeedsLayout()
subTitleView.setNeedsLayout()
titleView.layoutIfNeeded()
subTitleView.layoutIfNeeded()
//獲取子視圖的高度
titleView.frame.size.height = titleView.myHeight
subTitleView.frame.origin.y = titleView.frame.maxY
subTitleView.frame.size.height = subTitleView.myHeight
}
var myHeight: CGFloat {
get {
return subTitleView.frame.maxY
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/311705.html
標籤:
上一篇:試圖通過AVPlayer在uitableview中播放音樂,但播放的是錯誤的音樂(從Firebase加載錯誤的音樂)。




