I'm trying to create a table view cell prototype (similar to one below) programmatically.
The designed the cell with two stack views,
a) a vertical stack view to contain the text labels and,
b) a horizontal stack view to contain the image view & vertical stack view
I create the required views, stuff it in stack view, and pin stack view to table cell's contentView in the init() of tableviewcell.
And from cellForItemAtIndexPath I call configureCell() to populate data of the cell.
My init() looks like this
override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
textStackView = UIStackView(arrangedSubviews: [priorityNameLabel, descriptionLabel])
textStackView.axis = .vertical
textStackView.alignment = .leading
textStackView.distribution = .fill
textStackView.spacing = 5
containerStackView = UIStackView(arrangedSubviews: [priorityImageView, textStackView])
containerStackView.axis = .horizontal
containerStackView.alignment = .center
containerStackView.spacing = 5
containerStackView.distribution = .fill
contentView.addSubview(containerStackView)
containerStackView.translatesAutoresizingMaskIntoConstraints = false
pinContainerToSuperview()
}
func pinContainerToSuperview() {
containerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).activate()
containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor).activate()
containerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).activate()
containerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).activate()
}
In my view controller, I set tableView rowHeight to automaticDimension and estimated height to some approx. value. When I run the code, all I'm getting is,
The narrow horizontal lines on the top of the image are my tableview cells (My data count is 3 in this case). I couldn't figure out the problem. Can someone point out what's going wrong here?
EDIT 1:
These are the instance members of my TableViewCell class
var containerStackView: UIStackView!
var textStackView: UIStackView!
var priorityImageView: UIImageView! {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFit
return imageView
}
var priorityNameLabel: UILabel! {
let label = UILabel()
return label
}
var descriptionLabel: UILabel! {
let label = UILabel()
return label
}
You have your labels and image view as computed properties - this means that every time you access them a new instance is created. This is bad. This basically means that when you set them as arranged subvies of your stack views and then try to configure them later, you work on different objects.
Simplest solution would be to create your labels and image view the way you create your stack views in init.
Related
I faced weird issue while handling UICollectionView
I Created simple custom UICollectionViewCell, which has only one imageView and Label:
There's default placeholder image for Cell's imageView and updating imageView.image from collectionView(_:cellForItemAt:). But When image is set, all subview of cell disappears:
(Cells are not disappear at same time because downloading & setting image is async)
Note: Sample data I used is not wrong (Same data works for TableView in same app)
Why this happens and how can I fix it?
this is Sample data I used:
let movies = [
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955),
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955),
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955),
MovieFront(title: "Spider-Man: No Way Home", posterPath: "1g0dhYtq4irTY1GPXvft6k4YLjm.jpg", genre: "Genre", releaseDate: "2021-12-15", ratingScore: 8.4, ratingCount: 3955)
]
this is my part of ViewController:
lazy var collectionView = { () -> UICollectionView in
// FlowLayout
var flowLayout = UICollectionViewFlowLayout()
flowLayout.headerReferenceSize = CGSize(width: self.preferredContentSize.width, height: 180)
flowLayout.sectionInset = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
flowLayout.minimumInteritemSpacing = 20
flowLayout.minimumLineSpacing = 20
// Collection View
var collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: flowLayout)
collectionView.register(DiscoverCollectionViewCell.self, forCellWithReuseIdentifier: identifiers.discover_collection_cell)
collectionView.register(DiscoverCollectionHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: identifiers.discover_collection_header)
collectionView.backgroundColor = UIColor(named: Colors.background)
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.title = "Discover"
collectionView.dataSource = self
collectionView.delegate = self
self.view.backgroundColor = UIColor(named: Colors.background)
self.view.addSubview(collectionView)
collectionView.snp.makeConstraints { $0.edges.equalTo(self.view.safeAreaLayoutGuide) }
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
// Sample Cell
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifiers.discover_collection_cell, for: indexPath) as? DiscoverCollectionViewCell else { return DiscoverCollectionViewCell() }
let movie = movies[indexPath.row]
cell.movieTitle.text = movie.title
DispatchQueue.global().async {
guard let imageURL = URL(string: "https://image.tmdb.org/t/p/original/\(movie.posterPath)") else { return }
guard let imageData = try? Data(contentsOf: imageURL) else { return }
DispatchQueue.main.sync {
cell.posterImage.image = UIImage(data: imageData)
}
}
return cell
}
and this is my custom CollectionViewCell, I used Snapkit, Then library:
class DiscoverCollectionViewCell: UICollectionViewCell {
//MARK: Create properties
lazy var posterImage = UIImageView().then {
$0.image = UIImage(named: "img_placeholder")
$0.contentMode = .scaleAspectFit
}
lazy var movieTitle = UILabel().then {
$0.font = UIFont.systemFont(ofSize: 15)
$0.textColor = .white
$0.numberOfLines = 2
$0.minimumScaleFactor = 10
}
override init(frame: CGRect) {
super.init(frame: frame)
// add to view
self.addSubview(posterImage)
self.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
}
movieTitle.snp.makeConstraints { make in
make.top.equalTo(posterImage.snp.bottom).offset(5)
make.bottom.greaterThanOrEqualToSuperview()
make.leading.equalTo(posterImage.snp.leading)
make.trailing.equalTo(posterImage.snp.trailing)
}
self.backgroundColor = .blue
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Two issues with your cell's layout...
// add to view
self.addSubview(posterImage)
self.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
make.top.left.right.equalToSuperview()
}
You should always add UI elements to the cell's .contentView, not to the cell itself.
You did not constrain the bottom of the image view.
// add to ContentView!
self.contentView.addSubview(posterImage)
self.contentView.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
make.top.left.right.bottom.equalToSuperview()
}
Edit
You were missing a couple things from your post (including how you're setting your cell / item size), so while the above changes do fix the image not showing at all, it's not quite what you're going for.
I'm assuming you're setting the flow layout .itemSize somewhere, so your original constraints - without adding .bottom. to the image view constraints - were close...
When you add an image to a UIImageView, the intrinsicContentSize becomes the size of the image. Your constraints are controlling the width, but...
This constraint on your label:
make.bottom.greaterThanOrEqualToSuperview()
means "put the Bottom of the label at the Bottom of its superview or farther down!"
When your image loads, it sets the image view Height to its own Height and pushes the label way down past the bottom of the cell.
That line needs to be:
make.bottom.equalToSuperview()
That will prevent the Bottom of the label from moving.
Next, you need to tell auto-layout "don't compress or stretch the label vertically":
// prevent label from stretching vertically
movieTitle.setContentHuggingPriority(.required, for: .vertical)
// prevent label from compressing vertically
movieTitle.setContentCompressionResistancePriority(.required, for: .vertical)
Without that, the label will be compressed down to Zero height.
I find it very helpful to add comments so I know what I'm expecting to happen:
override init(frame: CGRect) {
super.init(frame: frame)
// add to ContentView
self.contentView.addSubview(posterImage)
self.contentView.addSubview(movieTitle)
//MARK: Add Constraints
posterImage.snp.makeConstraints { make in
// constrain image view to
// Top / Left / Right of contentView
make.top.left.right.equalToSuperview()
}
// prevent label from stretching vertically
movieTitle.setContentHuggingPriority(.required, for: .vertical)
// prevent label from compressing vertically
movieTitle.setContentCompressionResistancePriority(.required, for: .vertical)
movieTitle.snp.makeConstraints { make in
// constrain Top of label to Bottom of image view
// because we've set Hugging and Compression Resistance on the label,
// this will "pull down" the bottom of the image view
make.top.equalTo(posterImage.snp.bottom).offset(5)
// constrain Bottom of label to Bottom of contentView
// must be EQUAL TO
//make.bottom.greaterThanOrEqualToSuperview()
make.bottom.equalToSuperview()
// Leading / Trailing equal to image view
make.leading.equalTo(posterImage.snp.leading)
make.trailing.equalTo(posterImage.snp.trailing)
}
self.backgroundColor = .blue
}
Now we get this result:
and after the images download:
One final thing - although you may have already done something to address this...
As you see in those screenshots, setting .numberOfLines = 2 on a label does not force a 2-line height... it only limits it to 2 lines. If a Movie Title is short, the label height will be shorter as seen in the 2nd cell.
One way to fix that would be to constrain the label height to something like 2.5 lines by adding this to your init:
if let font = movieTitle.font {
movieTitle.snp.makeConstraints { make in
make.height.equalTo(font.lineHeight * 2.5)
}
}
That will give this output:
Although I am not sure, Because collection view cells are being reused the init of cells only gets called at the first time, not the time when image data is getting loaded from the server.
Try moving your layout-related code(specifically adding subviews and constraining them) in a different method of the cell and call it every time image gets loaded.
I have a view controller created in the storyboard and the it contains (check image for reference)
ScrollerView
a. StackViewA (image: green)
i. LabelA
ii. LabelB
b. StackViewB (image: green)
i. LabelC
ii. LabelD
I am fetching data from the API and am able to show that data in those labels.
Now, the 3rd set of data that I am fetching is dynamic, meaning it can be 2 more StackView (image: red) under the second StackView or 3 more etc.
I am guessing that I have the add that StackView programmatically in the controller inside the loop so that is created according to the loop.
Currently my 3rd StackView is also created in the storyboard and therefore it is showing only the last data from 3rd set after looping through them.
How do I solve that?
More specifically:
How can I add a StackView inside the ScrollerView created in the storyboard.
How do I contains it to position itself below the 2nd StackView also created in the storyboard.
Update
class InfoDetailsViewController: UIViewController {
// MARK: - Outlets
#IBOutlet weak var infoStack: UIStackView!
#IBOutlet weak var mainScroll: UIScrollView!
static var apiResp: APIDetailsResponse.APIReturn?
let infos: [APIDetailsResponse.Info] = (APIDetailsViewController.apiResp?.content?.infos)!
override func viewDidLoad() {
super.viewDidLoad()
infoStack.spacing = 25.0
for info in infos {
let addInfoTitle = UILabel()
addInfoTitle.font = .preferredFont(forTextStyle: .body)
addInfoTitle.backgroundColor = .orange
addInfoTitle.translatesAutoresizingMaskIntoConstraints = false
let addInfoContent = UITextView()
addInfoContent.font = .preferredFont(forTextStyle: .body)
addInfoContent.backgroundColor = .green
addInfoContent.translatesAutoresizingMaskIntoConstraints = false
addInfoTitle.text = "\(String(describing: (info.info_title)!))"
let htmlString = "\(String(describing: (info.information)!))"
// works even without <html><body> </body></html> tags, BTW
let data = htmlString.data(using: String.Encoding.unicode)!
let attrStr = try? NSAttributedString(
data: data,
options: [NSAttributedString.DocumentReadingOptionKey.documentType: NSAttributedString.DocumentType.html],
documentAttributes: nil)
addInfoContent.attributedText = attrStr
let childStackView = UIStackView(arrangedSubviews: [addInfoTitle, addInfoContent])
childStackView.alignment = .fill
childStackView.axis = .vertical
childStackView.distribution = .fill
childStackView.spacing = 5.0
childStackView.translatesAutoresizingMaskIntoConstraints = false
infoStack.addArrangedSubview(childStackView)
}
}
Currently I have this. What is happening now is no matter how many data the array is returning, I am always getting title and content for the first one and only title for each consecutive data.
So the best solution is when you create your scrollview add a stack view inside it. And whenever you are creating stack view dynamically add under that stack view which is inside scrollview.
So in this case you new stack view will gets stacked under your outer stack view in proper manner.
ScrollView -> 1 Stackview -> Multiple Dynamic stack views in loop
lets say you already have stack view named ParentStackview from your storyboard. Then follow these steps
lazy var childStackView: UIStackView = {
let stackView = UIStackView()
stackView.alignment = .center
stackView.axis = .vertical
stackView.distribution = .equalCentering
stackView.spacing = 30.0
return stackView
}()
public func viewDidLoad() {
ParentStackview.alignment = .center
ParentStackview.axis = .vertical
ParentStackview.distribution = .equalCentering
ParentStackview.spacing = 10.0
for eachChild in data {
ParentStackView.addArrangedSubview(childStackView)
childStackView.translatesAutoresizingMaskIntoConstraints = false
childStackView.widthAnchor.constraint(equalTo: securityScrollView.widthAnchor)
//set height too
// this below function you can use to add eachChild data to you child stackview
configureStackview(childstackView, eachChild)
}
}
Enjoy!
I wish to have 2 labels on custom table view cell. First label should be on left 15 points away from left margin and 2nd label should be on right 15 points away from right margin. It can grow internally. Since the label is not going to display lots of data, it surely won't overlap on each other.
I am using stack view. Below are the images for my custom xib file. Number of lines for both the label is set to 1. When I launch, I see a blank cell without the labels. What is missing?
EDIT: Adding more details. I updated distribution on UIStackView to Fill Equally and updated alignment for 2nd label i.e start time label to right. I am seeing the data on the cell now, but 2nd label is not getting aligned to right.
Code in cellForRow:
let cell = tableView.dequeueReusableCell(withIdentifier: "displayStartTime") as! ScheduleDisplayStartTimeCustomCell
cell.selectionStyle = UITableViewCell.SelectionStyle.gray
cell.titleLabel.text = "Start"
cell.timeLabel.text = startTime
return cell
This is how it looks now after the edit:
Storyboard solution:
You can select the distribution for the StackView to equal spacing in the storyboard, with the default spacing value. The Labels only need the height contraint after that (or you could set the height for the StackView), and will be positioned to the sides of the StackView.
Resulting cell
The text alignment in the Label won’t matter, as the Label will be only as wide as needed.
I do not use storyboards that much but I know this works.
First you have to register the cell in your viewDidLoad:
tableView.register(ScheduleDisplayStartTimeCustomCell.self, forCellReuseIdentifier: "displayStartTime")
Then you can programmatically create a custom cell like this:
class ScheduleDisplayStartTimeCustomCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupView()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let startLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 1
label.textAlignment = .left
return label
}()
let timeLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 1
label.textAlignment = .right
return label
}()
func setupView() {
addSubview(startLabel)
addSubview(timeLabel)
NSLayoutConstraint.activate([
startLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
startLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 15),
timeLabel.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -15),
timeLabel.centerYAnchor.constraint(equalTo: centerYAnchor)
])
selectionStyle = UITableViewCell.SelectionStyle.gray
}
}
And finally you would set your cells like this :
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "displayStartTime") as! ScheduleDisplayStartTimeCustomCell
cell.startLabel.text = "Start"
cell.timeLabel.text = startTime
return cell
}
I have had similar issues in the past, the best solution I found it to assign a BackgroundColor to the labels (Blue, Red) and the StackView (Black). Then I see if the problem is with the constraints, or the UILabel text alignment properties.
Also, I noticed that you have an extension to UIViews, there may be something in there that is causing the problem.
Im new to iOS development and Im a bit confused as to how to achieve this.
I have 2 UILabels added to a UIStackView like so:
let horizontalStackView1 = UIStackView(arrangedSubviews: [self.label1, self.label2])
and when I run the app it looks like this:
However, Id like the labels to be next to each other with no spacing in between something like this:
Ive tried setting horizontalStackView1.distribution, horizontalStackView1.alignment etc with no luck.
How do I achieve this?
Thanks in advance!
UPDATE:
The code looks like this (its a cell of a table by the way):
class ItemTableViewCell: UITableViewCell
{
...
let stateLabel = UILabel()
let effectiveDateLabel = UILabel()
...
var typeImage: UIImage?
{
...
}
var summary: String?
{
...
}
var effectiveDate: Date?
{
...
}
override init(style: UITableViewCellStyle, reuseIdentifier: String?)
{
super.init(style: style, reuseIdentifier: reuseIdentifier)
self.accessoryType = .disclosureIndicator
...
let horizontalStackView1 = UIStackView(arrangedSubviews: [self.stateLabel, self.effectiveDateLabel])
let horizontalStackView2 = UIStackView(arrangedSubviews: [typeImageViewWrapper, self.titleLabel])
horizontalStackView2.spacing = 4
let verticalStackView = UIStackView(arrangedSubviews: [horizontalStackView1, horizontalStackView2, self.summaryLabel])
verticalStackView.axis = .vertical
verticalStackView.spacing = 4
self.contentView.addSubview(verticalStackView)
...
}
required init?(coder aDecoder: NSCoder)
{
fatalError()
}
}
That's because the UIStackView picks the first arrangedSubview with lowest content hugging priority and resizes it so the stackview's content takes up full width.
If you want to use UIStackView for this case, you can should change the content hugging priorities, eg.
label2.setContentHuggingPriority(.defaultLow, for: .horizontal)
label1.setContentHuggingPriority(.defaultHigh, for: .horizontal)
The stackviews distribution should be set to fillProportionally so every arranged subview keeps its proportions.
However, the remaining space is filled by the stackview automatically. To suppress this, you need to add an empty view at the end. This empty view needs a low content hugging priority so it can grow to fill up the space where the other views remain by their proportions.
Furthermore, the empty view needs an intrinsicContentSize for the stackview to compute the dimensions:
class FillView: UIView {
override var intrinsicContentSize: CGSize {
get { return CGSize(width: 100, height: 100) }
}
}
Now set your arranged subviews and put the fillView at the end
let fillView: UIFillView()
fillView.setContentHuggingPriority(priority: .fittingSizeLevel, for: .horizontal)
myStackView.addArrangedSubview(fillView)
Set the stackviews spacing to your needs to maintain the distance between the subviews.
I want 2 labels (say leftLabel, rightLabel) and place them horizontally such that leftLabel stretches and rightLabel just fits single character icon (say, ">"). Thus both labels layout justified. Like this...
This is the code I have -
class StackViewController: UIViewController {
/// Main vertical outer/container stack view that pins its edges to this view in storyboard (i.e. full screen)
#IBOutlet weak private var containerStackView: UIStackView!
private var leftLabel: UILabel = {
let leftLabel = UILabel(frame: .zero)
leftLabel.font = .preferredFont(forTextStyle: .body)
leftLabel.numberOfLines = 0 // no text truncation, allows wrap
leftLabel.backgroundColor = .orange
return leftLabel
}()
private var rightLabel: UILabel = {
let rightLabel = UILabel(frame: .zero)
rightLabel.font = .preferredFont(forTextStyle: .body)
// Set CHCR as high so that label sizes itself to fit the text
rightLabel.setContentHuggingPriority(UILayoutPriorityDefaultHigh, for: .horizontal)
rightLabel.setContentCompressionResistancePriority(UILayoutPriorityDefaultHigh, for: .horizontal)
rightLabel.backgroundColor = .green
return rightLabel
}()
override func viewDidLoad() {
super.viewDidLoad()
prepareAndLoadSubViews()
// Note, the text required to be set in viewDidAppear, not viewDidLoad, otherwise rightLabel stretches to fill!!
leftLabel.text = "This is left label text that may go in multiple lines"
rightLabel.text = ">" // Always a single character
}
/// Dynamically creates a horizontal stack view, with 2 labels, in the container stack view
private func prepareAndLoadSubViews() {
/// Prepare the horizontal label stack view and add the 2 labels
let labelStackView = UIStackView(arrangedSubviews: [leftLabel, rightLabel])
labelStackView.axis = .horizontal
labelStackView.distribution = .fillProportionally
labelStackView.alignment = .top
containerStackView.addArrangedSubview(labelStackView)
containerStackView.addArrangedSubview(UIView())
}
}
Which gives below result (i.e. leftLabel width is 0 in view debugger) -
NOTE: If I move text set code in viewDidAppear then it works fine.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Note, the text required to be set in viewDidAppear, not viewDidLoad, otherwise rightLabel stretches to fill!!
leftLabel.text = "This is left label text that may go in multiple lines"
rightLabel.text = ">" // Always a single character
}
Why?
And, can we set content hugging/ compression resistance priorities before viewDidLoad?
I played around with your code quite a bit but I was not able to make it work either. I think this is a bug that occurs when you add a UIStackView to another UIStackView. When you only have one UIStackView your code works fine.
So I cannot offer a fix for your case but IMHO you shouldn't really need to use a UIStackView for your 2 labels at all. UIStackView is great if you have multiple arranged subviews that you hide and show and need to be arranged automatically. For just two "static" labels I think it is a bit of an overkill.
You can achieve what you are after by adding your two labels to a UIView and then set layout constraints to the labels. It's really easy:
class StackViewController: UIViewController {
#IBOutlet weak var containerStackView: UIStackView!
private var leftLabel: UILabel = {
let leftLabel = UILabel(frame: .zero)
leftLabel.font = .preferredFont(forTextStyle: .body)
leftLabel.numberOfLines = 0
leftLabel.backgroundColor = .orange
leftLabel.translatesAutoresizingMaskIntoConstraints = false
leftLabel.numberOfLines = 0
return leftLabel
}()
private var rightLabel: UILabel = {
let rightLabel = UILabel(frame: .zero)
rightLabel.font = .preferredFont(forTextStyle: .body)
rightLabel.setContentHuggingPriority(UILayoutPriority.required, for: .horizontal)
rightLabel.backgroundColor = .green
rightLabel.translatesAutoresizingMaskIntoConstraints = false
return rightLabel
}()
override func viewDidLoad() {
super.viewDidLoad()
prepareAndLoadSubViews()
leftLabel.text = "This is left label text that may go in multiple lines"
rightLabel.text = ">"
}
private func prepareAndLoadSubViews() {
let labelContainerView = UIView()
labelContainerView.addSubview(leftLabel)
labelContainerView.addSubview(rightLabel)
NSLayoutConstraint.activate([
leftLabel.leadingAnchor.constraint(equalTo: labelContainerView.leadingAnchor),
leftLabel.topAnchor.constraint(equalTo: labelContainerView.topAnchor),
leftLabel.bottomAnchor.constraint(equalTo: labelContainerView.bottomAnchor),
rightLabel.leadingAnchor.constraint(equalTo: leftLabel.trailingAnchor),
rightLabel.topAnchor.constraint(equalTo: labelContainerView.topAnchor),
rightLabel.bottomAnchor.constraint(equalTo: labelContainerView.bottomAnchor),
rightLabel.trailingAnchor.constraint(equalTo: labelContainerView.trailingAnchor)
])
containerStackView.addArrangedSubview(labelContainerView)
containerStackView.addArrangedSubview(UIView())
}
}