Auto adjust font size for UITableView - ios

For one of my UITableView, to allow more text or large font size text to fit in the fields, I need to add or adjust font size.
I used a boolean for adjustsFontSizeToFitWidth. And clipsToBounds=true. But this does not always work for me, not sure why it's inconsistent, especially when you have bigger font size text to be included. Any correction?
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
let headerLabel = UILabel(frame: CGRect(x: 40, y: 0, width:
tableView.bounds.size.width, height: tableView.bounds.size.height))
headerLabel.textColor = UIColor.white
headerLabel.text = self.tableView(self.tableView, titleForHeaderInSection: section)
headerLabel.sizeToFit()
headerLabel.adjustsFontSizeToFitWidth = true
headerLabel.clipsToBounds=true
headerLabel.numberOfLines=0
headerLabel.lineBreakMode = NSLineBreakMode.byTruncatingTail
headerLabel.minimumScaleFactor = 0.2
headerView.addSubview(headerLabel)
return headerView
}

Delete the following may be?
headerLabel.sizeToFit()
This will allow to make 
adjustsFontSizeToFitWidth
 property working.

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if searching {
cell?.textLabel?.text = searchedLabour[indexPath.row]
cell?.textLabel?.sizeToFit()
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.numberOfLines = 2
cell?.textLabel?.lineBreakMode = NSLineBreakMode.byTruncatingTail
} else {
cell?.textLabel?.text = labourWordsArray[indexPath.row]
cell?.textLabel?.sizeToFit()
cell?.textLabel?.adjustsFontSizeToFitWidth = true
cell?.textLabel?.numberOfLines = 2
cell?.textLabel?.lineBreakMode = NSLineBreakMode.byTruncatingTail
}
return cell!
}

Related

UITableView.automaticDimension Not working tableView detailTextLabel

I am implementing UITableViewController Programmatically (No Storyboards!).
I tried many possible ways to implement automatic resizing of TableViewCell's detailTextLabel but none is working. I don't know what I am missing or whether it's a bug! Here's what I tried:
//Class - tableViewContoller
override func viewDidLoad() {
super.viewDidLoad()
setUpTableView()
}
func setUpTableView() {
tableView.tableFooterView = UIView(frame: CGRect.zero)
tableView.separatorColor = UIColor(red: 240.0/255.0, green: 240.0/255.0, blue: 240.0/255.0, alpha: 0.8)
tableView.contentInset = UIEdgeInsets(top: 10.0, left: 0.0, bottom: 10.0, right: 0.0)
tableView.dataSource = self
tableView.delegate = self
tableView.rowHeight = UITableView.automaticDimension
tableView.estimatedRowHeight = UITableView.automaticDimension //Tried 44 -> Not working either
tableView.reloadData()
}
//cellForRowAt IndexPath
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: UITableViewCell.CellStyle.value1, reuseIdentifier: cellId)
}
cell?.detailTextLabel?.numberOfLines = 0
cell?.detailTextLabel?.lineBreakMode = .byWordWrapping
cell?.selectionStyle = .none
switch indexPath.row {
case 0:
cell?.textLabel?.text = "Case 1"
cell?.detailTextLabel?.text = caseDetails?.details
case 1:
cell?.textLabel?.text = "Case 2"
cell?.detailTextLabel?.text = caseDetails?.bio
default:break
}
return cell!
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableView.automaticDimension
}
I have 2-3 cells where detailTextLabel may have multiple lines.
Please let me know what's that I'm missing here. What I figured after reading on the Internet is to add custom constraints, but I don't think that'll work either.
You have to add constraints for that cell?.detailTextLabel
cellForRowAt
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: cellId)
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: cellId)
}
cell?.detailTextLabel?.numberOfLines = 0
cell?.detailTextLabel?.lineBreakMode = .byWordWrapping
cell?.selectionStyle = .none
cell?.detailTextLabel?.layer.backgroundColor = UIColor.yellow.cgColor
// ALLOW MANUAL CONSTRAINTS
cell?.detailTextLabel?.translatesAutoresizingMaskIntoConstraints = false
// TOP +15, BOTTOM -15, RIGHT -15
cell?.detailTextLabel?.topAnchor.constraint(equalTo: (cell?.contentView.topAnchor)!, constant: 15).isActive = true
cell?.detailTextLabel?.bottomAnchor.constraint(equalTo: (cell?.contentView.bottomAnchor)!, constant: -15).isActive = true
cell?.detailTextLabel?.rightAnchor.constraint(equalTo: (cell?.contentView.rightAnchor)!, constant: -10).isActive = true
switch indexPath.row {
case 0:
cell?.textLabel?.text = "Case 1"
cell?.detailTextLabel?.text = "hi\nhello\nwelcome\nhow are you"
case 1:
cell?.textLabel?.text = "Case 2"
cell?.detailTextLabel?.text = "caseDetails?.bio\n\n\n123456"
default:break
}
return cell!
}
Output
Should work if you set your estimated row height to an actual value. You can't have both set to .automaticDimension.

getting the height of the custom cell in UITableViewCell

I'm creating a bubble chat like application. I created custom functions for the receiving and sending bubble chats.
After creating them, I've added them into the cells that I've created using the UITableView.
However, I am not able to set the height of the cell, depending on the height of the custom cell itself.
For example, some text passed in could be longer than the one before.
Thus I can't seem to set each cell according to the custom bubble chat height.
Please help!
This are my tableview functions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrMsg.count
}
// second
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 100
}
// lastly created
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for:indexPath)
if arrMsg[indexPath.row]["type"] as! String == "outgoing" {
cell.contentView.addSubview(createOutGoingBubble(msg: arrMsg[indexPath.row]["message"] as! String))
}
if arrMsg[indexPath.row]["type"] as! String == "incoming" {
cell.contentView.addSubview(createIncomingBubble(mymsg: arrMsg[indexPath.row]["message"] as! String))
}
return cell
}
This is how it looks currently
How do I set the height of the cell according to the custom bubble created inside the heightforrowat function?
Probably using the line to find the height and return it:
arrMsg[indexPath.row]["message"] as! String == "outgoing"
**This is my function to create the custom bubble chats to be added into the tableviewcell
func createOutGoingBubble(msg:String) -> UIView {
let subV = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height))
let label = UILabel()
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 18)
label.textColor = .white
label.text = msg
let constraintRect = CGSize(width: 0.66 * view.frame.width,
height: .greatestFiniteMagnitude)
let boundingBox = msg.boundingRect(with: constraintRect,
options: .usesLineFragmentOrigin,
attributes: [.font: label.font],
context: nil)
label.frame.size = CGSize(width: ceil(boundingBox.width),
height: ceil(boundingBox.height))
let bubbleSize = CGSize(width: label.frame.width + 28,
height: label.frame.height + 20)
let outgoingMessageView = UIImageView(frame:
CGRect(x: view.frame.width - bubbleSize.width - 20,
y: bubbleSize.height - 25,
width: bubbleSize.width,
height: bubbleSize.height))
let bubbleImage = UIImage(named: "outgoing")?
.resizableImage(withCapInsets: UIEdgeInsets(top: 17, left: 21, bottom: 17, right: 21),
resizingMode: .stretch)
.withRenderingMode(UIImage.RenderingMode.alwaysTemplate)
outgoingMessageView.image = bubbleImage
outgoingMessageView.tintColor = UIColor(red: 0.40 , green: 0.71, blue: 1.00, alpha: 1)
subV.addSubview(outgoingMessageView)
label.center = outgoingMessageView.center
subV.addSubview(label)
return subV
}
Thanks in advance!
You can use Autolayout for the same and get free from all the coding part. Just set the constraint of the inner view in association with the cell and then right the following code.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell:ChatSenderTableViewCell = (tableView.dequeueReusableCell(withIdentifier: "ChatSenderTableViewCell", for: indexPath) as? ChatSenderTableViewCell)!
cell.LabelChatMessage.text = "Your Message"
cell.LabelChatMessage.numberOfLines = 0
cell.LabelChatMessage.sizeToFit()
return cell
}
I am using a custom cell name ChatSenderTableViewCell to create a bubble like effect containing a label for messages send or receive.
Use label inside of view and use margin from top and bottom according to your desire. Also, you need to make 0 number of lines in UIlabel. you can do it by using label.numberoflines = 0.
Also, you need to add the following code to change the height of the row according to the text inside it.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
You can try this:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
guard let cell = tableView.cellForRow(at: indexPath) else { return 0 }
return cell.intrinsicContentSize.height
}
The intrinsicContentSize is the natural size for the receiving view, considering only properties of the view itself.

UITableViewCell - selected background size based on content

I have this code to get table cell
func getCell(_ tableView: UITableView) -> UITableViewCell? {
var cell:UITableViewCell? = tableView.dequeueReusableCell(withIdentifier: CELL_REUSE_ID)
if (cell == nil)
{
//init and configure the cell
cell = UITableViewCell(style: UITableViewCellStyle.default, reuseIdentifier: CELL_REUSE_ID)
let selectedView:UIView = UIView(frame: CGRect(x: 0, y: 0, width: cell!.frame.size.width, height: cell!.frame.size.height))
selectedView.backgroundColor = UIColor.black.withAlphaComponent(0.3)
let layer = selectedView.layer
layer.borderColor = UIColor.blue.cgColor
layer.borderWidth = getCellBorderWidth();
layer.cornerRadius = getCellCornerRadius();
layer.backgroundColor = UIColor.blue.cgColor
cell!.selectedBackgroundView = selectedView
}
return cell
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell:UITableViewCell? = getCell(tableView)
cell!.backgroundColor = UIColor.clear
cell!.textLabel!.textColor = UIColor.darkText
cell!.textLabel!.text = tableData[indexPath.row]
cell!.textLabel!.textAlignment = .right
cell!.textLabel!.numberOfLines = 1
cell!.textLabel!.adjustsFontSizeToFitWidth = true
return cell!
}
Cells and table are generated in code, no xibs. Now, If I select cell, the background is covering entire width of table. How can I do background for some cells, that is only half of the table width (or some other percentual ratio)?
I think U can add another view to selectedBackgroundView
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
// selectedBackgroundView
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor(white: 0, alpha: 0)
// add another view to selectedBackgroundView, and set any frame for this view
let selectView = UIView(frame: CGRect(x: 0, y: 0, width: 200, height: 40))
selectView.backgroundColor = .red
backgroundView.addSubview(selectView)
cell?.selectedBackgroundView = backgroundView
}
return cell!
}

ios seperatorView in tableView

I have added a seperator between cells to add spacing cell with separator
But when I change color of seperatorView to clearColor from blueColor it disappears,can someone help ?
Here's my code:
func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return 50
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell",forIndexPath: indexPath)
cell.textLabel?.text = "Hello World"
cell.textLabel?.textColor = UIColor.blackColor()
cell.backgroundColor = UIColor.clearColor()
let additionalSeperatorThickness = CGFloat(6)
let additionalSeperator = UIView(frame: CGRectMake(0,
cell.frame.size.height - additionalSeperatorThickness,
cell.frame.size.width,
additionalSeperatorThickness))
additionalSeperator.backgroundColor = UIColor.clearColor()
cell.addSubview(additionalSeperator)
let imageView = UIImageView(image: UIImage(named: "text_box_1_converted.png")!)
cell.backgroundView = imageView
cell.bringSubviewToFront(additionalSeperator)
return cell
}

UITableView - I want to display blank cell

I set up my tableView and has two springVar as shown in the image below. I want my tableview to show empty cells after the two springVar so that my solve bar is at the bottom of the screen. Any advices on how to go about it? My code is below.
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return springVar.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cellIdentifier = "Cell"
var cell = tableView.dequeueReusableCellWithIdentifier(cellIdentifier) as? UITableViewCell
if cell == nil {
cell = UITableViewCell(style: UITableViewCellStyle.Value2, reuseIdentifier: cellIdentifier)
}
cell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "cell")
var data : NSManagedObject = springVar[indexPath.row] as! NSManagedObject
cell!.textLabel!.text = "Spring \(indexPath.row + 1)"
var force : Float = data.valueForKey("force") as! Float
var stiffness : Float = data.valueForKey("stiffness") as! Float
cell!.detailTextLabel!.text = "Force =\(force) \t Stiffness =\(stiffness)"
cell!.detailTextLabel!.textColor = UIColor .darkGrayColor()
return cell!
}
i think this maybe helpfull
if indexPAth.row / 2 == 0
{
return UITableViewCell()
// u can customize ur cell to show a button or anything else
}
this show a custom/blank cell after each 2 cell,(odd)
You can add Footer view in your tableView this way:
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerView = UIView(frame: CGRectMake(0, 0, tableView.frame.size.width, 40))
footerView.backgroundColor = UIColor.whiteColor()
//add button in your footer view
var button = UIButton(frame: CGRectMake(0, 0, 75, 30))
button.setTitle("Solve", forState: UIControlState.Normal)
button.setTitleColor(UIColor.brownColor(), forState: UIControlState.Normal)
button.addTarget(self, action: "buttonTapAction:", forControlEvents: UIControlEvents.TouchUpInside)
footerView.addSubview(button)
return footerView
}
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 40.0
}
And your result will be:
You can adjust the footerHeight according to your own needs.
override func tableView(tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
let footerHeight : CGFloat = (tableView.frame.size.height - (CGFloat(springVar.count) * 45.0) - 45.0 - 64.0)
let oneCell = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.size.width, height: footerHeight))
return oneCell
}
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
let footerHeight : CGFloat = (tableView.frame.size.height - (CGFloat(springVar.count) * 45.0) - 45.0 - 64.0)
return footerHeight
}

Resources