UIDatePicker not respecting autolayout constraints iOS 14 - swift

The new UIDatePicker style's doesn't appear to be respecting autolayout. It should be right aligned with the label expanding to take up the majority of the cell. Here is the code for the cell.
class DatePickerTableViewCell: UITableViewCell {
public let label = UILabel()
public let datePicker = UIDatePicker()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
// Cell settings
self.label.translatesAutoresizingMaskIntoConstraints = false
self.datePicker.translatesAutoresizingMaskIntoConstraints = false
// Add views
self.contentView.addSubview(self.label)
self.contentView.addSubview(self.datePicker)
// Constrain views
self.label.setContentHuggingPriority(.defaultLow - 1, for: .horizontal)
self.datePicker.setContentHuggingPriority(.defaultLow + 1, for: .horizontal)
NSLayoutConstraint.activate([
self.label.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
self.label.leadingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.leadingAnchor),
self.label.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor),
self.label.trailingAnchor.constraint(equalTo: self.datePicker.leadingAnchor, constant: -8),
self.datePicker.topAnchor.constraint(equalTo: contentView.layoutMarginsGuide.topAnchor),
self.datePicker.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor),
self.datePicker.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Here are some pictures showing what it is doing:
This is similar to this stack overflow question but doesn't appear to be fixed by their solution UIDatePicker with .compact style doesn't respect content hugging priority

Related

Custom UITableViewCell Constraints

I'm creating a chat using a UITable with custom cells for the chat bubbles. Like WhatsApp, I want some bubbles to be on the left, and some to be on the right.
I'm using dequeueReusableCell(withIdentifier identifier: String) -> UITableViewCell?, which calls the cell's init(style:reuseIdentifier:) method so setup my cell with:
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
cellBackground = UIView()
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .clear
setupConstraints()
}
func setupConstraints() {
NSLayoutConstraint.activate([
cellBackground.topAnchor.constraint(equalTo: contentView.topAnchor),
cellBackground.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
cellBackground.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
cellBackground.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.5)
])
}
but this isn't satisfactory. The cell is always on the left, due to the leadingAnchor constraint - when the cell is on the right it needs to be a trailingAnchor constraint.
If I use a setup function for the cell, should setupConstraints be called there, or should the init setup the constraints it knows about at that time? Alternatively, should these constraints all be set up in layoutSubviews()?
Add 2 instance variables as a references to the leading and trailing constraints inside the cell custom class
var leadCon,traCon:NSLayoutConstraint!
Then inside init also but out of the activate
leadCon = cellBackground.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
leadCon.isActive = true
And
traCon = cellBackground.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
traCon.isActive = true
According to what you need add a func
func toLeft(_ value:Bool) {
if value {
leadCon.isActive = true
traCon.isActive = false
}
else {
leadCon.isActive = false
traCon.isActive = true
}
}
And call it after dequeue line in cellForRowAt

How to access the correct cell width inside a UITabelViewCell Class?

I am trying to obtain the correct width for a custom cell inside a UITableViewCell Class. I tried the below:
import UIKit
import ChameleonFramework
class IsectionsCustomTableViewCell: UITableViewCell {
let cellContainer: UIView = {
let container = UIView()
container.backgroundColor = UIColor.flatPink()
container.translatesAutoresizingMaskIntoConstraints = false
return container
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(cellContainer)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func applyAppropriateSizeAndConstraintsForCellItems() {
NSLayoutConstraint.activate([
cellContainer.topAnchor.constraint(equalTo: self.topAnchor),
cellContainer.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -1*((self.frame.size.width)/2)),
cellContainer.bottomAnchor.constraint(equalTo: self.bottomAnchor),
cellContainer.leftAnchor.constraint(equalTo: self.leftAnchor)
])
}
}
However, as it can be seen from the attached image, the below line of code used above did not return the correct width as the total width was not split equally in half:
-1*((self.frame.size.width)/2)
Any idea what did I do wrong here, how can I obtain the true width of the custom Cell, which in my mind should be equal to the width of the Table it is going to be placed inside?
Regards,
Shadi Hammoudeh.
Do base the constraint on the frame. Use the proper constraint.
Change:
cellContainer.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -1*((self.frame.size.width)/2))
to:
cellContainer.rightAnchor.constraint(equalTo: cellContainer.superview.centerXAnchor)

Obtaining UILabel width when not occupying full screen width?

I would like to obtain the width of a UILabel added as a subView inside a custom TableView Cell. The TableView Class I am using is listed below:
import UIKit
class customTableViewCell: UITableViewCell {
let customLabel: UILabel = {
let label = UILabel()
label.translateAutoConstraints = false
label.textAlignment = .left
return label
}()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(customLabel)
customLabel.topAnchor.constraint(equal: contentView.topAnchor).isActive = true
customLabel.leftAnchor.constraint(equal: contentView.leftAnchor, constant: 10).isActive = true
customLabel.rightAnchor.constraint(equal: contentView.rightAnchor, constant: (contentView.frame.size.width/2)-10-customLabel.frame.size.width).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError(“init(coder:) has not been implemented”)
}
}
However, from the above code when I assigned the rightAnchor constraint for the customLabel UILabel, Xcode did not return the correct width of the UILabel I was looking for.
I understand that I only specified the top and left constraints for the UILabel. I also know that UILabel by default has intrinsic layout on, that it can decide on the required height based on the content of the UILabel. However, I am wondering if I did not set the numberOfLines for the customUILabel defined in the above code as 0 (i.e., I only want my text inside the UILabel to occupy one line only). Can I obtain the width of the customUILabel before the text got truncated.
Let me explain further, if my customLabel has a lot of text, it will occupy the full width of the screen then gets truncated. However, if it does not contain a lot of text, then it’s width will be less than the width of the screen. And this is exactly what I am interested in obtaining, the width of the UILabel used to display the small text inside it?
Regards,
Shadi.
You need
self.contentView.rightAnchor.constraintGreaterThanOrEqualToAnchor(customLabel.rightAnchor, constant: 8.0).active = true
Then print the width inside
override func layoutSubviews() {
super.layoutSubviews()
print(customLabel.frame.width)
}
Don't use frames in constraints calculations
(contentView.frame.size.width/2)-10-customLabel.frame.size.width
Inside cell init they not yet calculated

Snapkit and multiple custom cells in TableView

I am using UItableView as a base for a user profile page. I have several custom cells. The first custom cell is images wrapped in scrollview. I have this error when I open this view:
"<SnapKit.LayoutConstraint:0x1c42a2940#CardFullscreenViewController.swift#143 UIScrollView:SCROLL_VIEW.top == Lez.ProfileImagesCell:0x12a02e800.top>",
"<SnapKit.LayoutConstraint:0x1c02a9180#CardFullscreenViewController.swift#144 UIScrollView:SCROLL_VIEW.height == 512.0>",
"<SnapKit.LayoutConstraint:0x1c02a91e0#CardFullscreenViewController.swift#145 UIScrollView:SCROLL_VIEW.bottom == Lez.ProfileImagesCell:0x12a02e800.bottom - 16.0>",
"<NSLayoutConstraint:0x1c0094690 'UIView-Encapsulated-Layout-Height' Lez.ProfileImagesCell:0x12a02e800'ProfileImagesCell'.height == 44 (active)>"
And here is a custom code for this cell:
class ProfileImagesCell: UITableViewCell {
var scrollView = UIScrollView()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupScrollView()
layoutIfNeeded()
}
private func setupScrollView() {
addSubview(scrollView)
let x = frame.width * 1.6
scrollView.snp.makeConstraints { (make) in
make.top.left.right.equalToSuperview()
make.height.equalTo(x)
make.bottom.equalToSuperview().inset(16)
}
scrollView.snp.setLabel("SCROLL_VIEW")
scrollView.auk.settings.contentMode = .scaleAspectFill
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
I assume there is something wrong with height, but I can't solve this. Any input is appretiated.
Reason behind this conflict UIView-Encapsulated-Layout-Height is initial height of the cell , you can try to set the priority of the bottom constraint of the scrollView to 999 , I mean this one
make.bottom.equalToSuperview().inset(16)

ContentView for tableViewCell not auto-resizing correctly?

I have added 2 labels to my cell and setup these constraints with snapkit, issue is I cant get the cell to expand correctly, it stays at its default height:
titleLabel.snp.makeConstraints { (make) -> Void in
make.top.equalTo(contentView.snp.top)
make.bottom.equalTo(descriptionLabel.snp.top)
make.left.equalTo(contentView.snp.left)
make.right.equalTo(contentView.snp.right)
}
descriptionLabel.snp.makeConstraints { (make) -> Void in
make.top.equalTo(titleLabel.snp.bottom)
make.bottom.equalTo(contentView.snp.bottom)
make.left.equalTo(contentView.snp.left)
make.right.equalTo(contentView.snp.right)
}
I mapped the four edges as you can see, however I know height isnt implied by these, how can I apply a height when the content is by nature, dynamic, and could be various heights...
setup for the labels looks like this:
lazy var titleLabel: UILabel = {
let titleLabel = UILabel()
titleLabel.textColor = .green
titleLabel.textAlignment = .center
contentView.addSubview(titleLabel)
return titleLabel
}()
lazy var descriptionLabel: UILabel = {
let descriptionLabel = UILabel()
descriptionLabel.textColor = .dark
descriptionLabel.textAlignment = .center
descriptionLabel.numberOfLines = 0
contentView.addSubview(descriptionLabel)
return descriptionLabel
}()
Give the table view an estimatedRowHeight, and set its rowHeight to UITableViewAutomaticDimension. Now the cells will be self-sizing. Well, if a label is pinned by all four sides to the content view, and if the cell is self-sizing, then that's all you have to do: the label will automatically change its height to accommodate its text, and the cell will automatically change size to accommodate the label.
First of all I think that you should add subviews to contentView in subclassed UITableViewCell class initializer method.
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.contentView.addSubview(titleLabel)
self.contentView.addSubview(descriptionLabel)
}
Secondly, make sure that in your viewDidLoad method (probably in your ViewController) these two lines are added:
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableView.automaticDimension
Of course, you should change estimatedRowHeight to accommodate your needs.
One more thing worth mentioning - you can create these constraints easier (using power of SnapKit):
titleLabel.snp.makeConstraints { (make) -> Void in
make.top.left.right.equalTo(contentView)
}
descriptionLabel.snp.makeConstraints { (make) -> Void in
make.top.equalTo(titleLabel.snp.bottom)
make.bottom.left.right.equalTo(contentView)
}