在iOS 12中,我的水平堆栈视图(包含三个元素)的布局恰好:
但是在iOS 11中,这三个元素相互叠加:
这里是包含集合视图的视图控制器,其中一行包含堆栈:
struct TestStackConstants {
static let rowHeight:CGFloat = 200.0
static let heightPerHoursLine:CGFloat = 16.0
}
public struct OpenHours: Equatable {
public let instrument: String
public let openStrings: [String] // ex: ["00:00 - 17:00", "17:15 - 24:00"]
public let dayOfWeek: String // ex: Wednesday
public let timeZone: String // ex: GMT-04:00
}
class TSViewController: UIViewController {
fileprivate var extendedCollection: UICollectionView!
fileprivate var myTimeZone = "GMT-0:400"
fileprivate var dailyHours = [OpenHours]()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
let day1 = OpenHours(instrument: "USD/CAD", openStrings: ["00:00 - 12:00", "12:05 - 24:00"], dayOfWeek: "Monday", timeZone: "GMT-04:00")
let day2 = OpenHours(instrument: "USD/CAD", openStrings: ["00:00 - 24:00"], dayOfWeek: "Tuesday", timeZone: "GMT-04:00")
let day3 = OpenHours(instrument: "USD/CAD", openStrings: ["00:00 - 24:00"], dayOfWeek: "Wednesday", timeZone: "GMT-04:00")
dailyHours = [day1, day2, day3]
}
private func setupView() {
let myLayout = UICollectionViewFlowLayout()
extendedCollection = UICollectionView(frame: .zero, collectionViewLayout: myLayout)
extendedCollection.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(extendedCollection)
NSLayoutConstraint.activate([
extendedCollection.topAnchor.constraint(equalTo: self.view.topAnchor),
extendedCollection.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
extendedCollection.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
extendedCollection.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
extendedCollection.backgroundColor = .gray
extendedCollection.dataSource = self
extendedCollection.delegate = self
extendedCollection.register(TSHoursInfoCell.self, forCellWithReuseIdentifier: "infoCell")
}
}
// MARK: - Extensions
extension TSViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "infoCell", for: indexPath) as! TSHoursInfoCell
cell.marketTitle.text = "MARKET HOURS (" + myTimeZone + ")"
if self.dailyHours.count > 0 {
for (item, hours) in zip(cell.threeDays, dailyHours) {
item.dayOfWeek.text = hours.dayOfWeek.uppercased()
item.hoursHeightConstraint.constant = CGFloat(hours.openStrings.count) * TestStackConstants.heightPerHoursLine
item.dailyTime.text = hours.openStrings.joined(separator: "\n")
}
}
return cell
}
}
extension TSViewController: UICollectionViewDelegate { /*...*/ }
extension TSViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let returnSize = CGSize(width: collectionView.bounds.size.width, height: TestStackConstants.rowHeight)
return returnSize
}
}
这是收集单元格的定义,其中包含标题和堆栈:
struct HoursConstants {
static let insetting:CGFloat = 24.0
static let titleSmallFont = UIFont.systemFont(ofSize: 12.0)
static let titleSmallBoldFont = UIFont.boldSystemFont(ofSize: 12.0)
static let hoursWidth:CGFloat = 96.0
}
class TSHoursInfoCell: UICollectionViewCell {
public var marketTitle: UILabel!
public var threeDays: [TSHoursDailyView]!
fileprivate let horizStack: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.distribution = .fillEqually
stackView.alignment = .center
stackView.spacing = 0.0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .gray
marketTitle = UILabel(frame: .zero)
marketTitle.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(marketTitle)
NSLayoutConstraint.activate([
marketTitle.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10.0),
marketTitle.heightAnchor.constraint(equalToConstant: 20.0),
marketTitle.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: HoursConstants.insetting),
marketTitle.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -HoursConstants.insetting)
])
marketTitle.font = HoursConstants.titleSmallBoldFont
marketTitle.textColor = .orange
marketTitle.textAlignment = .left
contentView.addSubview(horizStack)
NSLayoutConstraint.activate([
horizStack.topAnchor.constraint(equalTo: marketTitle.bottomAnchor, constant: 7.0),
horizStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: HoursConstants.insetting),
horizStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -HoursConstants.insetting)
])
threeDays = [TSHoursDailyView(), TSHoursDailyView(), TSHoursDailyView()]
horizStack.addArrangedSubview(threeDays[0])
horizStack.addArrangedSubview(threeDays[1])
horizStack.addArrangedSubview(threeDays[2])
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class TSHoursDailyView: UIView {
public var dayOfWeek: UILabel!
public var dailyTime: UILabel!
public var hoursHeightConstraint: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
dayOfWeek = UILabel(frame: .zero)
dayOfWeek.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(dayOfWeek)
NSLayoutConstraint.activate([
dayOfWeek.topAnchor.constraint(equalTo: self.topAnchor, constant: 5.0),
dayOfWeek.heightAnchor.constraint(equalToConstant: 16.0),
dayOfWeek.widthAnchor.constraint(equalToConstant: HoursConstants.hoursWidth)
])
dayOfWeek.font = HoursConstants.titleSmallBoldFont
dayOfWeek.textColor = .white
dayOfWeek.textAlignment = .left
dailyTime = UILabel(frame: .zero)
dailyTime.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(dailyTime)
NSLayoutConstraint.activate([
dailyTime.topAnchor.constraint(equalTo: dayOfWeek.bottomAnchor, constant: 5.0),
dailyTime.widthAnchor.constraint(equalToConstant: HoursConstants.hoursWidth)
])
hoursHeightConstraint = dailyTime.heightAnchor.constraint(equalToConstant: 24.0)
hoursHeightConstraint.isActive = true
dailyTime.font = HoursConstants.titleSmallFont
dailyTime.numberOfLines = 0
dailyTime.textColor = .white
dailyTime.textAlignment = .left
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
我看不到特定于iOS 12的任何内容;他们为什么布置不同?
答案 0 :(得分:3)
我很惊讶您的代码在iOS 12+上产生的结果,但是确实如此。
主要问题是dayOfWeek
和dailyTime
标签缺少x位置约束。
我进行了其他一些更改,可能会有所帮助...而不是使用硬编码/计算的hoursHeightConstraint.constant
,而是添加了一个底部约束,以便它使用该标签的固有高度。
这是12点以上的结果
以及11
和修改后的代码(只需查找// DonMag: ...
注释-只有少数几个,但是将整个内容发回到'cha:更加可靠)
struct TestStackConstants {
static let rowHeight:CGFloat = 200.0
static let heightPerHoursLine:CGFloat = 16.0
}
public struct OpenHours: Equatable {
public let instrument: String
public let openStrings: [String] // ex: ["00:00 - 17:00", "17:15 - 24:00"]
public let dayOfWeek: String // ex: Wednesday
public let timeZone: String // ex: GMT-04:00
}
class TSViewController: UIViewController {
fileprivate var extendedCollection: UICollectionView!
fileprivate var myTimeZone = "GMT-0:400"
fileprivate var dailyHours = [OpenHours]()
override func viewDidLoad() {
super.viewDidLoad()
setupView()
let day1 = OpenHours(instrument: "USD/CAD", openStrings: ["00:00 - 12:00", "12:05 - 24:00"], dayOfWeek: "Monday", timeZone: "GMT-04:00")
let day2 = OpenHours(instrument: "USD/CAD", openStrings: ["00:00 - 24:00"], dayOfWeek: "Tuesday", timeZone: "GMT-04:00")
let day3 = OpenHours(instrument: "USD/CAD", openStrings: ["00:00 - 24:00"], dayOfWeek: "Wednesday", timeZone: "GMT-04:00")
dailyHours = [day1, day2, day3]
}
private func setupView() {
let myLayout = UICollectionViewFlowLayout()
extendedCollection = UICollectionView(frame: .zero, collectionViewLayout: myLayout)
extendedCollection.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(extendedCollection)
NSLayoutConstraint.activate([
extendedCollection.topAnchor.constraint(equalTo: self.view.topAnchor),
extendedCollection.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
extendedCollection.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
extendedCollection.trailingAnchor.constraint(equalTo: self.view.trailingAnchor)
])
extendedCollection.backgroundColor = .gray
extendedCollection.dataSource = self
extendedCollection.delegate = self
extendedCollection.register(TSHoursInfoCell.self, forCellWithReuseIdentifier: "infoCell")
}
}
// MARK: - Extensions
extension TSViewController: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "infoCell", for: indexPath) as! TSHoursInfoCell
cell.marketTitle.text = "MARKET HOURS (" + myTimeZone + ")"
if self.dailyHours.count > 0 {
for (item, hours) in zip(cell.threeDays, dailyHours) {
item.dayOfWeek.text = hours.dayOfWeek.uppercased()
// DonMag: remove -- using label intrinsic height
// item.hoursHeightConstraint.constant = CGFloat(hours.openStrings.count) * TestStackConstants.heightPerHoursLine
item.dailyTime.text = hours.openStrings.joined(separator: "\n")
}
}
return cell
}
}
extension TSViewController: UICollectionViewDelegate { /*...*/ }
extension TSViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let returnSize = CGSize(width: collectionView.bounds.size.width, height: TestStackConstants.rowHeight)
return returnSize
}
}
struct HoursConstants {
static let insetting:CGFloat = 24.0
static let titleSmallFont = UIFont.systemFont(ofSize: 12.0)
static let titleSmallBoldFont = UIFont.boldSystemFont(ofSize: 12.0)
static let hoursWidth:CGFloat = 96.0
}
class TSHoursInfoCell: UICollectionViewCell {
public var marketTitle: UILabel!
public var threeDays: [TSHoursDailyView]!
fileprivate let horizStack: UIStackView = {
let stackView = UIStackView()
stackView.axis = .horizontal
stackView.distribution = .fillEqually
// DonMag: changed alignment
stackView.alignment = .top // .center
stackView.spacing = 0.0
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .gray
marketTitle = UILabel(frame: .zero)
marketTitle.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(marketTitle)
NSLayoutConstraint.activate([
marketTitle.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10.0),
marketTitle.heightAnchor.constraint(equalToConstant: 20.0),
marketTitle.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: HoursConstants.insetting),
marketTitle.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -HoursConstants.insetting)
])
marketTitle.font = HoursConstants.titleSmallBoldFont
marketTitle.textColor = .orange
marketTitle.textAlignment = .left
contentView.addSubview(horizStack)
NSLayoutConstraint.activate([
horizStack.topAnchor.constraint(equalTo: marketTitle.bottomAnchor, constant: 7.0),
horizStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: HoursConstants.insetting),
horizStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -HoursConstants.insetting)
])
threeDays = [TSHoursDailyView(), TSHoursDailyView(), TSHoursDailyView()]
horizStack.addArrangedSubview(threeDays[0])
horizStack.addArrangedSubview(threeDays[1])
horizStack.addArrangedSubview(threeDays[2])
// DonMag: un-comment to clearly see the view frames
// threeDays[0].backgroundColor = .red
// threeDays[1].backgroundColor = .blue
// threeDays[2].backgroundColor = .brown
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class TSHoursDailyView: UIView {
public var dayOfWeek: UILabel!
public var dailyTime: UILabel!
// DonMag: remove -- use label bottomAnchor to determine height
// public var hoursHeightConstraint: NSLayoutConstraint!
override init(frame: CGRect) {
super.init(frame: frame)
dayOfWeek = UILabel(frame: .zero)
dayOfWeek.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(dayOfWeek)
NSLayoutConstraint.activate([
dayOfWeek.topAnchor.constraint(equalTo: self.topAnchor, constant: 5.0),
dayOfWeek.heightAnchor.constraint(equalToConstant: 16.0),
dayOfWeek.widthAnchor.constraint(equalToConstant: HoursConstants.hoursWidth),
// DonMag: added -- needed x-position
dayOfWeek.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0),
])
dayOfWeek.font = HoursConstants.titleSmallBoldFont
dayOfWeek.textColor = .white
dayOfWeek.textAlignment = .left
dailyTime = UILabel(frame: .zero)
dailyTime.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(dailyTime)
NSLayoutConstraint.activate([
dailyTime.topAnchor.constraint(equalTo: dayOfWeek.bottomAnchor, constant: 5.0),
dailyTime.widthAnchor.constraint(equalToConstant: HoursConstants.hoursWidth),
// DonMag: added -- needed x-position
dailyTime.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 0.0),
// DonMag: added -- use label height to determine height of view
dailyTime.bottomAnchor.constraint(lessThanOrEqualTo: self.bottomAnchor, constant: -5.0),
])
// DonMag: remove -- use label bottomAnchor to determine height
// hoursHeightConstraint = dailyTime.heightAnchor.constraint(equalToConstant: 24.0)
// hoursHeightConstraint.isActive = true
dailyTime.font = HoursConstants.titleSmallFont
dailyTime.numberOfLines = 0
dailyTime.textColor = .white
dailyTime.textAlignment = .left
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}