Can we able to set the multiline label with left and right side as image. please check the attached image.
Yes, I am using tableview cell xib. Need to do this with constraints.
I tried
left imageview - leading, width, height, vertically in container
second label - top, bottom , leading to first image , trailing to second image. number of lines = 0.
right image view embed with UIView - this is for when select the image background colour changed to blue with checkmark image
constraint - trailing, width , height , vertically in container
The issue is label is getting truncated when large text is there.
After that,I tried to remove the width of second image, but getting constraint issue.
Please help me to resolve this issue.
Thankyou in advance.
The cell can be prevented from performing dynamic auto-resizing for a variety of reasons:
Constraints could be preventing dynamic height:
To confirm the constraints, run the app in the debugger, then tap on the “Debug View Hierarchy” button and confirm the constraints. It is a quick way to see all the constraints (and make sure there are not any that you did not intend):
If you had some extraneous constraint (e.g., an unintended height combined with top/bottom), that could cause the label to not grow in height to fit the text.
The table view could be defined to not support automatic dimension of the cells:
Another possible source of the problem is the table view’s row height was set to some fixed value, preventing the label from expanding to fit the text. Confirm that the table view’s row height is set to automaticDimension. Either in IB:
Or, programmatically:
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = 44
}
You could have something in code that is forcing a particular cell height:
Needless to say, make sure you are not implementing a specific height in tableView(_:heightForRowAt:). The use of automaticDimension, above, means that you should not implement this delegate method at all.
Maybe the number of lines is getting reset to 1.
While in the view debugger, look at the properties for the label, and make sure the numberOfLines is still set to zero. Make sure there isn’t some code somewhere that is resetting the numberOfLines.
Not that it is relevant, but this is the code that generated the above image. Not much here to see, admittedly:
class ViewController: UIViewController {
#IBOutlet weak var tableView: UITableView!
var strings = [
"This is a very long string that goes on and on. This is so long that it will take a few lines. This one takes four lines, but the next one takes only one.",
"This is short string.",
"This is a very long string that goes on and on."
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UINib(nibName: "CustomCell", bundle: nil), forCellReuseIdentifier: "CustomCell")
}
}
extension ViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return strings.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.customLabel.text = strings[indexPath.row]
return cell
}
}
Related
Here is the UITableView that I want to make:
In order to achieve this, I divided contentView of cell into three parts.
1 - fromView: contains start time and class type. Height will be 30% of contentView
2 - infoView: contains clock image, class name and professor's name. Height will be 40% of contentView.
3 - toView: contains end time and location. Height will be space that left(30%).
Firstly, before going to details, I decided to show this containers only. For understanding a problem, I painted them(green, red, blue respectively).
After adding them into the contentView, here are the constraints I gave to those containers:
fromView.easy.layout(Top(), Left(), Right(), Height(*0.3).like(contentView))
infoView.easy.layout(Top().to(fromView), Left(), Right(), Height(*0.4).like(contentView))
toView.easy.layout(Top().to(infoView), Left(), Right(), Bottom())
Seems like everything is right. After launching, I thought that I will see them, but here is what happened:
I thought that cell does not know what size it needs to be, so I decided to implement following function:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
After this, UITableView showed containers pretty correctly than before. But, I plan to add some UILabels and other views into that containers(look at first picture). In other words, I don't know what size a cell needs to have. It needs to be kind of dynamic. Anyway, I tried to add those labels into the containers, maybe after that, a cell will figure out the the height. Here is how I did it:
func setupViews() {
fromView.addSubviews(fromTime, classType)
toView.addSubviews(toTime, room)
infoView.addSubviews(clockImage, teacherName, subjectName)
contentView.addSubviews(toView, fromView, infoView)
}
func setupConstraints() {
fromView.easy.layout(Top(), Left(), Right(), Height(*0.3).like(contentView))
infoView.easy.layout(Top().to(fromView), Left(), Right(), Height(*0.4).like(contentView))
toView.easy.layout(Top().to(infoView), Left(), Right(), Bottom())
fromTime.easy.layout(CenterY(), Left(8))
fromTime.setContentHuggingPriority(.required, for: .horizontal)
fromTime.setContentCompressionResistancePriority(.required, for: .horizontal)
classType.easy.layout(CenterY(), Left(8).to(fromTime))
clockImage.easy.layout(CenterY(), Left(16), Width(24), Height(24))
subjectName.easy.layout(CenterY(-8), Left().to(classType, .left), Right())
teacherName.easy.layout(Top(8).to(subjectName), Left().to(subjectName, .left), Right())
toTime.easy.layout(CenterY(), Left(8))
toTime.setContentHuggingPriority(.required, for: .horizontal)
toTime.setContentCompressionResistancePriority(.required, for: .horizontal)
room.easy.layout(CenterY(), Left(8).to(toTime))
}
But anyway, problem appeared again like this:
I think, the problem is that I give height to containers according to height of contentView, but contentView does not know its height. But I also don't know what height it needs to have, cause it needs to depend according to size of labels. So, how to solve this problem?
Don't set heights for the containers. You have to make sure the top and bottom of the cell are connected through constraints. My recommendation is to just get rid of the containers, add all the labels and images to the cell directly, and create constraints like this.
Then set tableView.rowHeight = UITableView.automaticDimension, or return UITableView.automaticDimension from tableView(_:heightForRowAt:)
Try by giving height constraint to your main view inside your cell.
Look like what you want is a dynamic height calculated based on the content's AutoLayout. Update the delegates to return the UITableViewAutomaticDimension for the heightForRowAt and some good estimation, e.g., 150 for the estimatedHeightForRowAt:
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Then you can just set the content's size using autolayout, and the table will calculate the height of the cells for you dynamically.
Estimated height is used for scrolling purposes - a good estimate will provide you a good scrolling experience (dynamic height is calculated only when the cell is being displayed, thus for the yet undisplayed cells the tableView will use estimation when scrolling).
I am making a simple contacts application with controllers: ContactTableViewController and custome cell: ContactTableViewCell. I created a custom table view cell where the style is custom, identifier is ContactTableViewCell, and class is also ContactTableViewCell.
The cell has two UILabel fields, which are exposed to ContactTableViewCell.swift class as follows:
import UIKit
class ContactTableViewCell: UITableViewCell {
#IBOutlet weak var name: UILabel!
#IBOutlet weak var info: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
print("cell loaded with name: ", name)
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
Now I want to display them in my ContactViewController, and the relevant part of my controller looks like this:
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
// here we communicate with parts of the app that owns the data
override func tableView(_ tableView : UITableView
, cellForRowAt indexPath: IndexPath
) -> UITableViewCell {
let id = "ContactTableViewCell"
// deque a cell as an instance of ContactTableViewCell
guard let cell = tableView.dequeueReusableCell(withIdentifier: id, for : indexPath)
as? ContactTableViewCell else {
fatalError("dequed cell is not instance of ContactTableViewCell")
}
cell.name.text = "hello"
cell.info.text = "hello information"
However, when I run the simulation I only see two rows of "hello", even though it should be something like:
hello
hello information
repeated twice. What is the problem here?
Most probably you don't have enough room to fit both labels. You can either set the row height in storyboard by:
Selecting your tableview
Go to size inspector
Change the Row Height
OR
You can implement tableView(_:heightForRowAt:) method in your tableView's delegate. i.e.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
// return desired height for your cell
return 90.0
}
It is a contraint issue. You have to define height, width, x and y positioning for both the name UILabel and the info UILabel. Font size places a dominant role for height with UILabels and width can be based on the number of characters in the UILabel x font size so you do not have to explicity express height and width constraints for a UILabel, but for a UIButton you would have to explicitly define constraints for x,y,width,height. For UILabel we only have to define x and y constraints.
What happens when you do not clearly define the constraints for your UI elements is that the rendering of your View will have unpredictable results and UI elements quite often just do not appear on the view.
It looks like, from your code, you are using XCode designer to add your UILabels so that is what you can use to add constraints. You can also add constraints programmatically as well. But I am pretty sure you are using XCode Storyboard designer.
Whether programmatically or through XCode designer you need add a constraint for the name UILabel to the top and left of the super view, you can reposition later, and then constrain x and y alignment of the info UILabel to the name UILabel, horizontally aligning to the name UILabel and +8 vertical spacing to the bottom of the name UILabel, this will place the info UILabel below and centered to the name UILabel.
See this guide: https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/WorkingwithConstraintsinInterfaceBuidler.html
And this Stackoverflow answer: https://stackoverflow.com/a/34448801/1258525
Not the first two constraints I have circled in this picture, this defines the x and y for the Video Quality UILabel:
And then see how the next label below, Onset Threshold constraints itself to the leading edge of the Video Quality label and then the divider below the VideoQuality label:
My theory the 2nd label is truncated not getting sufficient width, and may be the number of lines in the second label is 1. Hence try setting number of line to 0 and check the width and auto layout constraints.
I have such problem, while trying to create a simple messenger.
Here what I came to:
class ChatBubleUIView that class is responsible for creating a bubleview with label in it. It works fine, calculating view height according to label height
Inside my cell I've created a content view. In the cell class, I'm adding new ChatBubleUIView instance as a subview to content View.
The problem is that, content doesn't scale up to the size of my ChatBubleInstance.
class ChatMessageTableViewCell: UITableViewCell, MessageCellConfiguration {
var message: Message?
override func awakeFromNib() {
super.awakeFromNib()
}
func configureCell() {
let chatBubleView = ChatBubleUIView(message: message!)
self.addSubview(chatBubleView)
}
}
In my tableView delegate
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "messageCell") as! ChatMessageTableViewCell
let data = currentUser.mesaageHistory[indexPath.row]
cell.message = data
cell.configureCell()
return cell
}
Also I have set estimated row height for my tableView
messageTableView.rowHeight = UITableViewAutomaticDimension
messageTableView.estimatedRowHeight = 44
What should I do to set to my tableView row height chatViewBubleUIView instance height.
Previously, I solved this problem using old-school approach, programmaticly determine chatViewBubleUIView instance height and then implement heightForRowAtIndexPath. But I'd like to do that using AutoLayoaut.
set your label's four constraint like top,bottom,leading,trailing and number of height of your label should be 0. Then it will automatically increased it's height as per content. If you are taking this label in any view then view's constrains should be same as label i have mentioned above!
Senario A:
If I set the label content in cellForRowAtIndexPath, the cell correctly get resized.
Senario B:
If I change the text content in custom action in cell, the cell sized does not get changed.(I do call setNeedsLayout + layoutIfNeeded)
How to fix this?
EDIT:
1) I have set,
myTableView.estimatedRowHeight = 71.0
myTableView.rowHeight = UITableViewAutomaticDimension
2) I have correctly added auto layout constraints.
I was running into this issue, and my problem was that I was constraining the content to self (the UITableViewCell) and not to self.contentView (the contentView OF the cell). Hope this helps someone else who has built their cells all in code!
In my case, the cell's custom size was enabled:
After you change the text of the cell, just reload that particular cell or simply call mainTableView.reloadData().
To reload that cell-
//indexPath is indexPath of cell you just changed label of
mainTableView.reloadRows(at: indexPath, with: .automatic)
In my case, in the same cell I had an imageView in the top left corner with a "center vertically in container" constraint, and a "top space container" constraint.
Obviously to satisfy this two constraint the cell must have an height equal to:
(height of the imageView / 2) + (length of the top space container constraint).
This height is not enough to fit the label text, so my label had only 1 line visible.
After I have deleted the imageView top constraint all went to the right place, in my case i wanted the image to be centered, if the image had to stay in the top left corner I had to take off the "center vertically in container" constraint.
I hope this can help someone.
First of all, I don't specifically know what was your action on UITableViewCell. So, I assume I do that in UITableViewCell selection.
The below answer only work on iOS 9 and above
But, for some reason, it failed to do it in iOS 8 until it scroll. So, I will update the answer for iOS 8.
I have seen you have used UITableView's estimatedRowHeight and rowHeight at your project. So,
Please check the following
Make sure UITableView's estimatedRowHeight and rowHeight include inside viewDidLoad()
Make sure your UILabel lines set to 0
Make sure there is no constraints about height for your UILabel and let the constraints be like that :
If there are other component also included, make sure only bottom and top space constraints included or top space to container margin and bottom space to container margin.
Every time that you want to update the cell, you have to reload tableView no matter what your current situation will be.
So, don't say anything yet before you try this sample project, #Rikh answer still work. May be you are going in wrong direction. Here's the solution. Please do as I said steps by steps and let me know if that didn't work out. You might need to share your sample project which is causing.
Sample Demo - DynamicCellDemo
UPDATE for iOS 8 : update the following code for iOS 8 users
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if #available(iOS 9, *) {
// do nothing
} else {
tblDynamic.reloadData()
}
}
what you can do is set the AutoLayout constraints for the label in present in the cell from all the sides that is from Top, Bottom, Leading and Trailing. Then add the following UITableViewDelegate method to your class.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 500
}
This will do the job. As now content in table view cell automatically adjusts the height of the cell.
Try this if it works:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
Add the following in your viewDidLoad()
-(void)viewDidLoad{
[super viewDidLoad];
tableView.rowHeight = UITableViewAutomaticDimension
tableView.estimatedRowHeight = 140
}
I've making a simple UITableViewCell prototype in a storyboard, but I'm having some issues with the self-sizing aspect. As you can see in the image below, the cell size increases, but the text doesn't move down. (It has 0 lines.) Here's the table's view controller.
import UIKit
class ViewController: UITableViewController {
let events = ["Kaufman Family Finished Project Reception", "Home Remodelers' Survival Guide", "Mori Family Mid-Construction Showcase"]
let locations = ["La Cañada Flintridge", "Claremont", "Claremont"]
override func viewDidLoad() {
super.viewDidLoad()
tableView.estimatedRowHeight = 70.0
tableView.rowHeight = UITableViewAutomaticDimension
tableView.reloadData()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return events.count;
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier("EventCell") as EventTableViewCell
cell.eventName.text = events[indexPath.row]
cell.eventLocation.text = locations[indexPath.row]
return cell
}
}
Obviously I can't provide you with dozens of screenshots of the storyboard, so comment if you need other information. Here's some basic pictures though.
Hard to tell from the constraint diagram... for this arrangement to work you need:
Event Name label set to 0 lines (you said you do)
Event Name label set to word wrap (by default it isn't)
Event Name label constrained to top of cell and leading/trailing edges of cell
Event Name label bottom constrained to top of Event Location label
Same conditions for Event Location label - word wrap, 0 lines, if you want it to have variable number of lines
Event Location label constrained to bottom of cell and leading/trailing edges of cell
This should allow both labels to dynamically size their height and for the cell to size itself to accommodate the label heights and margins.
One last thing... you are calling sizeToFit on the label after setting the text, right?
Here are some images from a project of mine where resizing labels work:
Final result:
"Questions Here" is the label being changed.
Size Inspector
Properties Inspector