Design time crash while using programmatic constraints and #IBDesignable - swift

I've been spinning my wheels for a couple days on this. I can't find any demonstrations of programmatic constraints with #IBDesignable.
If I try imgv.translatesAutoresizingMaskIntoConstraints = false. Then an apparent infinite loop is set and I literally have to quit Xcode, reopen it and quickly delete it before design time occurs.
As it is currently written, I have constraints that should change the imgv size to 200 width and height, but changing the values to 300 has no effect on the storyboard. So It is as if the constraints have no effect.
QUESTION: How can I create programmatic constraints which would display on storyboard using #IBDesignable?## Heading ##
import UIKit
#IBDesignable
class tryTVCellTableViewCell: UITableViewCell {
override func prepareForInterfaceBuilder() {
setProperties()
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setProperties()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setProperties()
}
public override func layoutSubviews() {
super.layoutSubviews()
setProperties()
}
func setProperties() {
backgroundColor = .blue
let imgv = UIImageView(frame: CGRect(x: 10, y: 20, width: 50, height: 50))
let bundle = Bundle(for: type(of: self))
let img = UIImage(named: "mountain", in: bundle, compatibleWith: traitCollection)
assert(img != nil)
imgv.image = img
imgv.backgroundColor = .green
let lab = UILabel(frame: CGRect(x: 100, y: 10, width: 300, height: 300))
lab.text = "hkjlkjlkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;lkj;l;lkjk;j;i"
addSubview(imgv)
addSubview(lab)
imgv.widthAnchor.constraint(equalToConstant: 200).isActive = true
imgv.heightAnchor.constraint(equalToConstant: 200).isActive = true
imgv.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
}
}

Just try adding again
imgv.translatesAutoresizingMaskIntoConstraints = false
after
addSubview(lab)
before
imgv.widthAnchor.constraint(equalToConstant: 200).isActive = true
It should work.

Related

Adjusting UILabels size (i.e., width and height) inside a UITableViewCell Class?

I created a custom UITableViewCell Class as illustrated below, whereby i defined the items I would like to be displayed inside my custom cell (specifically UILabel items):
import UIKit
import ChameleonFramework
class IsectionsCustomTableViewCell: UITableViewCell {
let sectionDesignationLabelTopPadding: CGFloat = 10
let sectionDesignationLabelLeftPadding: CGFloat = 10
let sectionDesignationLabelRightPadding: CGFloat = 10
let depthOfSectionLabelTopPadding: CGFloat = 0
let depthOfSectionLabelLeftPadding: CGFloat = 10
let depthOfSectionLabelRightPadding: CGFloat = 10
let webThicknessLabelTopPadding: CGFloat = 10
let webThicknessLabelLeftPadding: CGFloat = 10
let webThicknessLabelRightPadding: CGFloat = 10
var sectionDesignationLabel: UILabel = {
let label = UILabel()
label.backgroundColor = UIColor.yellow
label.textAlignment = .left
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor(hexString: "#F27E63")
return label
}()
var depthOfSectionLabel: UILabel = {
let label = UILabel(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
label.backgroundColor = UIColor.blue
label.translatesAutoresizingMaskIntoConstraints = false
label.textColor = UIColor(hexString: "#F27E63")
return label
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
addSubview(sectionDesignationLabel)
addSubview(depthOfSectionLabel)
applyAppropriateSizeAndConstraintsForCellItems()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func applyAppropriateSizeAndConstraintsForCellItems() {
sectionDesignationLabel.frame.size.width = 200
NSLayoutConstraint.activate([
sectionDesignationLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: sectionDesignationLabelLeftPadding),
sectionDesignationLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -1*sectionDesignationLabelRightPadding),
sectionDesignationLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: sectionDesignationLabelTopPadding),
depthOfSectionLabel.topAnchor.constraint(equalTo: sectionDesignationLabel.bottomAnchor, constant: depthOfSectionLabelTopPadding),
depthOfSectionLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: depthOfSectionLabelLeftPadding),
depthOfSectionLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -1 * (((self.frame.size.width)/2) + depthOfSectionLabelRightPadding)),
])
}
}
As it can be seen from the declaration of depthOfSectionLabel, whereby I stated the width and height of its frame. However, these values are not reflected when my table gets displayed (please refer to attached image). The width is displayed much more greater than the 50 I specified for this specific label?
My question is how can I adjust the widths of the various labels to be displayed inside my tableView custom Cell?

How dynamic cell height increase using card view in swift

How to resolve the cell height and based on the text dynamic text
My code:
class NotificationTableViewCell: UITableViewCell {
var notification:Notifications? {
didSet {
guard let notificationList = notification else {return}
if let title = notificationList.title{
titleLabel.text = title
}
if let message = notificationList.Message {
descriptionLabel.text = " \(message) "
}
}
}
let ContentView = UIViewFactory()
.build()
//MARK: - cell title Label
let titleLabel = CustomLabel(text: "")
.changeNumberOfLines(lines: 1)
.buildUI()
//MARK: - cell description Label
let descriptionLabel = CustomLabel(text: "")
.changeTextAlignment(.left)
.changeLineBreakMode(mode: .byWordWrapping)
.changeFont(12)
.buildUI()
//MARK: - Time Label
let timeLabel = CustomLabel(text: "")
.buildUI()
//MARK: - IDPal Logo
let logo : UIImageView = {
let imageView = UIImageView()
imageView.image = UIImage(named: "idpal")
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
logo.contentMode = .scaleAspectFit
selectionStyle = .none
setUp()
}
//MARK: - SetUpViews
func setUp() {
addSubview(logo)
addSubview(titleLabel)
addSubview(descriptionLabel)
setUpConstraints()
}
override func layoutSubviews() {
super.layoutSubviews()
let cornerRadius: CGFloat = 10
contentView.clipsToBounds = true
contentView.layer.masksToBounds = false
contentView.layer.shadowColor = UIColor(red: 0.74, green: 0.74, blue: 0.74, alpha: 0.50).cgColor
contentView.layer.cornerRadius = cornerRadius
contentView.backgroundColor = UIColor(red: 1.00, green: 1.00, blue: 1.00, alpha: 1)
contentView.layer.borderWidth = 1.0
contentView.layer.borderColor = UIColor.lightGray.cgColor
contentView.alpha = 1
contentView.frame = contentView.frame.inset(by: UIEdgeInsets(top: 2, left: 0, bottom: 0, right: 0))
//set the values for top,left,bottom,right margins
// let margins = UIEdgeInsets(top: 3, left: 0, bottom: 10, right: 0)
// contentView.frame = contentView.frame.inset(by: margins)
}
func setUpConstraints() {
// containerView.topAnchor.constraint(equalTo:topAnchor).isActive = true
// containerView.leftAnchor.constraint(equalTo:leftAnchor).isActive = true
// containerView.rightAnchor.constraint(equalTo:rightAnchor).isActive = true
// containerView.bottomAnchor.constraint(equalTo:bottomAnchor).isActive = true
//MARK: - IDPal Logo constraints
logo.topAnchor.constraint(equalTo:topAnchor,constant:10).isActive = true
logo.leftAnchor.constraint(equalTo:leftAnchor,constant:14).isActive = true
logo.widthAnchor.constraint(equalToConstant:30).isActive = true
logo.heightAnchor.constraint(equalToConstant:40).isActive = true
//MARK: - titleLabel constraints
titleLabel.topAnchor.constraint(equalTo:logo.topAnchor,constant:0).isActive = true
titleLabel.leftAnchor.constraint(equalTo:logo.rightAnchor,constant:10).isActive = true
titleLabel.rightAnchor.constraint(equalTo:rightAnchor).isActive = true
//MARK: - descriptionLabel constraints
descriptionLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
descriptionLabel.leftAnchor.constraint(equalTo: titleLabel.leftAnchor).isActive = true
descriptionLabel.bottomAnchor.constraint(equalTo: bottomAnchor,constant:10).isActive = true
descriptionLabel.rightAnchor.constraint(equalTo: titleLabel.rightAnchor).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Hear my code can't able to configure if found any suggestion drop here please.
adding the border with it's to be space between contendview but not working for me.
I would like to give shadow effect like card similar to the image in my iOS app
thanks

Adjusting UILabel height depending on contents?

I have a custom CollectionViewCell class, which contains a label and an image. Basically, the image will be constrained to the left, top and right of the cell. However, I want its height to vary depending on the height of the UILabel, which in turns is going to be dependent on the contents inside it. Below is my attempt at it:
import UIKit
class CustomCollectionViewCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .yellow
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
convenience init(cellTextTile text: String) {
self.init()
}
func setupCustomCellElements(cellImageName image: String, cellTitleTextColour textColour: UIColor, cellTitleTextSize textSize: CGFloat, cellTitleFontType fontType: String, cellTitle title: String) {
let cellImage: UIImageView = {
let imageView = UIImageView()
imageView.backgroundColor = .clear
imageView.image = UIImage(named: image)
imageView.translatesAutoresizingMaskIntoConstraints = false
return imageView
}()
let cellTitle: UILabel = {
let label = UILabel()
label.textColor = textColour
label.font = UIFont(name: fontType, size: textSize)
label.text = title
label.textAlignment = .center
label.frame.size = CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)
label.numberOfLines = 0
label.lineBreakMode = NSLineBreakMode.byWordWrapping
label.sizeToFit()
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
addSubview(cellImage)
addSubview(cellTitle)
NSLayoutConstraint.activate([
cellTitle.bottomAnchor.constraint(equalTo: bottomAnchor),
cellTitle.leftAnchor.constraint(equalTo: leftAnchor),
cellTitle.rightAnchor.constraint(equalTo: rightAnchor),
cellImage.bottomAnchor.constraint(equalTo: cellTitle.topAnchor),
cellImage.topAnchor.constraint(equalTo: topAnchor),
cellImage.leftAnchor.constraint(equalTo: leftAnchor),
cellImage.rightAnchor.constraint(equalTo: rightAnchor)
])
}
}
However, with the above code I am not getting the kind of behaviour I am looking for. I want the height of the UIlabel to change based on its contents. And in turn the height of the image to adjust accordingly?
Regards,
Shadi.
You need a height constraint for the imageView
cellImage.heightAnchor.constraint(equalToConstant: 50), // or any value
Also don't add the properties inside the method setupCustomCellElements make them an instance variables , and add them inside the init function
It's better also to add the views to
contentView.addSubview(cellImage)
contentView.addSubview(cellTitle)
and constrcut the constraints with it

Changing items within custom UITableViewCell Class

I have 2 classes - a UITableViewController and a custom UITableViewCell. I want to change the cell height for my UITableViewController, so I implement the following:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.frame.height*(1/12)
}
and it works! The cell height changes. Now, I go into my custom UITableViewCell class
import UIKit
class TableViewCell: UITableViewCell {
var time:UILabel = UILabel()
var name:UILabel = UILabel()
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) // the common code is executed in this super call
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.frame.width*0.22, height: self.frame.height))
imageView.image = UIImage(named: "Person")
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = true
self.addSubview(imageView)
let tap = UITapGestureRecognizer(target: self, action: #selector(signIn))
imageView.addGestureRecognizer(tap)
name = UILabel(frame: CGRect(x: self.frame.width*0.22, y: 0, width: self.frame.width*0.78, height: self.frame.height*0.7))
name.textColor = UIColor.gray
name.font = UIFont(name: name.font!.fontName, size: 30)
name.adjustsFontSizeToFitWidth = true
self.addSubview(name)
time = UILabel(frame: CGRect(x: self.frame.width*0.22, y: self.frame.height*0.65, width: self.frame.width*0.78, height: self.frame.height*0.3))
time.textColor = UIColor.gray
time.font = UIFont(name: time.font!.fontName, size: 15)
time.adjustsFontSizeToFitWidth = true
self.addSubview(time)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
#objc func signIn(tap: UITapGestureRecognizer) {
let tappedImage = tap.view as! UIImageView
tappedImage.image = UIImage(named: "PersonClocked")
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
So, I now edit the function inside my controller to call the cells.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! TableViewCell
cell.layer.borderColor = UIColor.red.cgColor
cell.layer.borderWidth = 1
cell.name.text = names[indexPath.row]
cell.time.text = times[indexPath.row]
return cell
}
I expect it to all work now! But, it doesn't. For whatever reason, the methods get called in this order...
tableview(cellForRowAt) -> TableViewCell(override init) -> tableView(heightForRowAt)'
So, when I go to run it, it looks something like below. The cell is created with Swift's/Apple's default runtime tableView, then the cell size is changed, but everything inside the cell is still the size of the original default value. I need it to be the size of the cell. Any ideas?
Note - I added a border so you could see the size of the cell compared to the items.
Frame layout can't help in creating dynamic height tables you have to use dynamic tableViewCells and create the cell's contentView with constraints to get the height change with the current content
//
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) // the common code is executed in this super call
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: self.frame.width*0.22, height: self.frame.height))
imageView.image = UIImage(named: "Person")
imageView.contentMode = .scaleAspectFit
imageView.isUserInteractionEnabled = true
self.addSubview(imageView)
let tap = UITapGestureRecognizer(target: self, action: #selector(signIn))
imageView.addGestureRecognizer(tap)
name = UILabel(frame: CGRect(x: self.frame.width*0.22, y: 0, width: self.frame.width*0.78, height: self.frame.height*0.7))
name.textColor = UIColor.gray
name.font = UIFont(name: name.font!.fontName, size: 30)
name.adjustsFontSizeToFitWidth = true
self.addSubview(name)
time = UILabel(frame: CGRect(x: self.frame.width*0.22, y: self.frame.height*0.65, width: self.frame.width*0.78, height: self.frame.height*0.3))
time.textColor = UIColor.gray
time.font = UIFont(name: time.font!.fontName, size: 15)
time.adjustsFontSizeToFitWidth = true
self.addSubview(time)
imageView.translatesAutoresizingMaskIntoConstraints = false
name.translatesAutoresizingMaskIntoConstraints = false
time.translatesAutoresizingMaskIntoConstraints = false
imageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor,constant: 0).isActive = true
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 20).isActive = true
imageView.heightAnchor.constraint(equalToConstant: 30).isActive = true
imageView.widthAnchor.constraint(equalToConstant: 30).isActive = true
name.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 20).isActive = true
name.leadingAnchor.constraint(equalTo: imageView.leadingAnchor,constant: 20).isActive = true
name.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: -20).isActive = true
time.topAnchor.constraint(equalTo: name.topAnchor,constant: 20).isActive = true
time.leadingAnchor.constraint(equalTo: imageView.leadingAnchor,constant: 20).isActive = true
time.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: -20).isActive = true
time.bottomAnchor.constraint(equalTo: contentView.bottomAnchor,constant: -20).isActive = true
}
//
put this in viewDidLoad
tableview.estimatedRowHeight = 100
tableview.rowHeight = UITableViewAutomaticDimension
and don't implement heightForRowAt method

Why can't I see the constraint on this label?

I'm subclassing an UIView, and I want to add a constraint inside it. But when I do this, I'm not able to add any constraint :
class A19: UIView {
let titleLabel : UILabel = {
let label = UILabel()
label.text = "test"
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 414, height: 250))
backgroundColor = .black
addSubview(titleLabel)
titleLabel.topAnchor.constraint(equalTo: topAnchor, constant: 20).isActive = true
titleLabel.sizeToFit()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
What's wrong with that?
edit : So I'm putting the playground so everyone see that I'm not crazy !
Your view works. In the playground, you need to add:
view.layoutIfNeeded()
after creating the view to kick Auto Layout into action.