UITableView cell detailTextLabel text alignment not working - ios

I'm trying to format the position of numbers in a UIViewController's detailTextLabel property. The numbers in the detailTextLabel part of the UIViewTable are too far to the right (as in the image).
I've tried:
cell.detailTextLabel?.textAlignment = .center
but it doesn't work. I've tried .left, .right, .justified and various settings in interface builder.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PracticeWord", for: indexPath)
let sortedPracticeWord = sortedPracticeWords[indexPath.row]
print("practiceWord is: \(sortedPracticeWord)")
let split = sortedPracticeWord.components(separatedBy: "::")
cell.textLabel?.text = split[0]
cell.textLabel?.textColor = UIColor.white
cell.selectedBackgroundView = UIView()
cell.selectedBackgroundView!.backgroundColor = UIColor(white: 1, alpha: 0.20)
cell.textLabel?.text = split[1]
cell.detailTextLabel?.text = split[2]
cell.detailTextLabel?.textAlignment = .center
print("cell is: \(cell)")
return cell
}
I would like each number to end just under the 'g' of the word 'wrong'.

I think what's happening here is that the detailTextLabel is being sized to fit the text length, and the whole label aligned to the right edge.
I'd try adding a whitespace to the text that you add to the detail text label.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "PracticeWord", for: indexPath)
let sortedPracticeWord = sortedPracticeWords[indexPath.row]
print("practiceWord is: \(sortedPracticeWord)")
let split = sortedPracticeWord.components(separatedBy: "::")
cell.textLabel?.text = split[0]
cell.textLabel?.textColor = UIColor.white
cell.selectedBackgroundView = UIView()
cell.selectedBackgroundView!.backgroundColor = UIColor(white: 1, alpha: 0.20)
cell.textLabel?.text = split[1]
cell.detailTextLabel?.text = split[2] + " "
cell.detailTextLabel?.textAlignment = .center
print("cell is: \(cell)")
return cell
}

The detail text label is only displayed with the built in UITableViewCell styles, and it's not going to respect the alignment because the default styles will do their own thing and won't give you that much control. Which is just fine for simple stuff but quickly becomes a limitation for anything nontrivial.
If you want to control placement you'll need to define your own custom table cell with left and right UILabels, and constrain them exactly where you want them. Also bear in mind that if the user changes the system font size, you still may not line up with the 'g' character, so you might want to consider a different design, or just not worrying about that alignment.
See https://developer.apple.com/documentation/uikit/uitableviewcell/cellstyle for a description of the built in styles, but I suspect you'll need to create your own if the default style isn't doing what you want.

After creating custom cells by following this tutorial:
creating custom tableview cells in swift
It seems to be giving me what I originally intended.

Related

How does one prevent labels of different Swift cells displaying on top of each other?

Screenshot of the double text label
Current constraints of the label
Complete Hirearchy
What is my relevant code currently
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? ViewControllerTableViewCell {
let immy = cell.viewWithTag(1) as? UIImageView
let person: Userx = people[indexPath.row]
let text = person.Education
cell.lblName.text = person.Education. ///key line
cell.lblName.text = text?.uppercased()
cell.lblName?.layer.masksToBounds = true
let person5 = colorArray[indexPath.row]
let person6 = colorArray1[indexPath.row]
let person7 = colorArray2[indexPath.row]
let like = cell.viewWithTag(3) as? UIButton
cell.backgroundColor = person5
like?.backgroundColor = person6
immy?.backgroundColor = person7
cell.lblName.baselineAdjustment = .alignCenters
cell.postID = self.people[indexPath.row].postID
cell.row = indexPath.row
cell.delegate = self
cell.delegate2 = self
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
like?.isUserInteractionEnabled = true
}
return cell
}
return UITableViewCell()
}
What have I tried:
In prepare for reuse, I tried lblName.text = "" and lblName.text = nil Didn't work.
I also tried in cellForRowAt:
cell.lblName.text = nil
if cell.lblName.text == nil{
cell.lblName.text = person.Education
}
I also tried to get it done by constraints, no luck.
What I think might be cause
This didn't happen before I changed from TableViewController scene to ViewController(with an output table) scene.
It also didn't happen before I set the cells to have different colors.
I got it to work by checking clear graphics context on label2.
i think your problem would solve if you check cell heights ,
check heightForCellAtRow Func
I havent seen at your cell class. That issue happens when you have constraints issues. Since the autolayout system is unable to calculate the height of the row, the height becomes 0, any change from that point forward might be wrong.
I would suggest you check the cell code, add the labels to the contentView (if they are not) and add constraints between them:
eg:
bottomLabel.topAnchor.constraint(equalTo: topLabel.bottomAnchor, constant: 8).isActive = true
also set the compression resistance for both labels to be .defaultHigh and if you have the height of the row hardcoded remove that.

How can I line up different UITableViewCell images and labels?

All I'm doing in my cellForRowAt is setting UITableViewCell's (no subclass) imageView?.image and textLabel?.text values (and fonts and colors). Setting an image via SF Symbols and text according to my model. To go into more detail, there are only three possible cell kinds: a workspace, the "Add Workspace" button, and the archive.
In the following screenshot, I've demonstrated with green lines how these views don't quite line up in a logical fashion. Text is misaligned between all three types of cells, and (annoyingly) the SF Symbols image for that boxy icon with an "add" (+) indicator is slightly wider than the standard image.
Can anyone help me with an easy fix for this that I'm simply just missing? I've already tried setting the imageViews' aspect ratios to 1:1 with constraints. That didn't affect anything.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: UITableViewCell
if indexPath.section == 0 {
cell = tableView.dequeueReusableCell(withIdentifier: "workspace", for: indexPath)
if indexPath.row == addWorkspaceRow {
cell.imageView?.image = .addWorkspace
cell.imageView?.tintColor = cell.tintColor
cell.textLabel?.text = "Add Workspace"
cell.textLabel?.textColor = cell.tintColor
cell.accessoryType = .none
} else {
let workspace = model.workspaces[indexPath.row]
cell.imageView?.image = .workspace
cell.imageView?.tintColor = .label
cell.textLabel?.text = workspace.displayName
cell.textLabel?.textColor = .label
cell.accessoryType = .disclosureIndicator
}
} else {
cell = tableView.dequeueReusableCell(withIdentifier: "archive", for: indexPath)
cell.imageView?.image = .archive
cell.imageView?.tintColor = .archive
cell.textLabel?.text = "Archive"
cell.textLabel?.textColor = .label
cell.accessoryType = .disclosureIndicator
}
cell.textLabel?.font = .preferredFont(forTextStyle: .body)
return cell
}
I meet the same things, and want to solve it without using custom cell. But it is hard to config the constraint without subclass it.
Eventually, I turn to use custom cell, it is simple to use, and in case you may need to add more stuff in your tableView cell, custom cell is the better place to go.
My code, yeah I'm making a music player now;)
class LibraryTableCell: UITableViewCell {
var cellImageView = UIImageView()
var cellLabel = UILabel()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: "libraryTableCell")
cellImageView.translatesAutoresizingMaskIntoConstraints = false
cellImageView.contentMode = .scaleAspectFit
cellImageView.tintColor = .systemPink
contentView.addSubview(cellImageView)
cellLabel.translatesAutoresizingMaskIntoConstraints = false
cellLabel.font = UIFont.systemFont(ofSize: 20)
contentView.addSubview(cellLabel)
NSLayoutConstraint.activate([
cellImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
cellImageView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8),
cellImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
cellImageView.widthAnchor.constraint(equalToConstant: 44),
cellLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
cellLabel.leadingAnchor.constraint(equalTo: cellImageView.trailingAnchor, constant: 10),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class LibraryViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var tableView = UITableView()
let cellTitles = ["Playlists", "Artists", "Albums", "Songs", "Genres"]
let imageNames = ["music.note.list", "music.mic", "square.stack", "music.note", "guitars"]
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
title = "Library"
navigationController?.navigationBar.prefersLargeTitles = true
tableView.delegate = self
tableView.dataSource = self
tableView.register(LibraryTableCell.self, forCellReuseIdentifier: "libraryTableCell")
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.rowHeight = 48
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor),
tableView.topAnchor.constraint(equalTo: g.topAnchor, constant: 20),
tableView.heightAnchor.constraint(equalTo: g.heightAnchor, multiplier: 0.6)
])
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return cellTitles.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "libraryTableCell", for: indexPath) as? LibraryTableCell else {
fatalError("Unable to dequeue libraryTableCell")
}
cell.accessoryType = .disclosureIndicator
let imageName = imageNames[indexPath.row]
cell.cellImageView.image = UIImage(systemName: imageName)
let title = cellTitles[indexPath.row]
cell.cellLabel.text = title
return cell
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
cell.separatorInset = UIEdgeInsets(top: 8, left: 20, bottom: 8, right: 8)
}
}
Changing contentMode property of UIImageView will do the trick:
cell.imageView?.contentMode = .scaleAspectFit
It's happening because the images themselves are not the correct dimensions.
Your image in tableviewCell is wrong contentMode. It is reason due to wrong layout of your label.
You have option to fix that problem:
Option1:
open file XIB tableviewCell and change content mode of UIImage
Option 2:
you can set by code:
yourUImage.contentMode = .scaleAspectFit
I searched a long time for solution for the problem you're describing, but sadly I haven't found any. The problem seems to be the native UIImageView in the UITableViewCell. There are essentially two workarounds:
A) Resize all images you use as table view cell icons to a certain width (e.g. 30 and height 44). Draw this space and center the icon (while keeping the original size)
B) Get used to Apple's "You can use our pre-built solution but if you want to change it even a tiny bit you have to re-build everything from the bottom up"-philosophy and just use custom cells for everything you do in the app. With a custom cell, you could simply set the imageView width to a certain value.
I wonder how they solved that problem in the iOS Mail app.

Add downward-pointing arrow in table view cell

I am looking for a way to implement the bottom arrow like in Apple's Activity app.
I couldn't find anything similar in cell accessory type.
cell.accessoryType = UITableViewCell.AccessoryType.none
cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
cell.accessoryType = UITableViewCell.AccessoryType.detailDisclosureButton
cell.accessoryType = UITableViewCell.AccessoryType.checkmark
cell.accessoryType = UITableViewCell.AccessoryType.detailButton
I know that I can insert a UIImage there but maybe there's a better solution for this problem. I am using the default disclosure indicator in other cells, so I want to keep the same design in my app.
The correct solution is adding a custom image asset and placing a UIImage in the cell's accessoryView.
A hacky solution -- that might not work -- that you could try would be to set the accessoryType to disclosureIndicator then try rotating the accessoryView by setting its transform to CGAffineTransform(rotationAngle: .pi / 2).
I don't think you can rotate the default disclosureIndicator.
Here comes the regular solution.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil) // dequeue as necessary
cell.backgroundColor = .lightGray
cell.textLabel?.text = "\(indexPath.row)"
let downArrow = UIImage(named: "down_arrow")
cell.accessoryView = UIImageView(image: downArrow)
return cell
}
White down arrow image at the end of this sentence.

table view cell selection color works after 0 cell but not first row?

I changed the tableview cell selection color and it works well only from row 1 and beyond but row 0 "first"doesn't it shows the default light gray color .
Is the way I did wrong?
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
// Configure the cell...
let colorView = UIView()
let green = UIColor(red:0.31, green:0.62, blue:0.53, alpha:1.0)
colorView.backgroundColor = green
UITableViewCell.appearance().selectedBackgroundView = colorView
cell.textLabel?.text = "#" + books[indexPath.row]
return cell
}
Do you realise, that you change all cells appearance with this call UITableViewCell.appearance().selectedBackgroundView = colorView? So, each time your table view asks for one cell, you create new view, call it colorView and replace the selectedBackgroundView for all previously created cells? You're doing it wong.
Move this
let colorView = UIView()
let green = UIColor(red:0.31, green:0.62, blue:0.53, alpha:1.0)
colorView.backgroundColor = green
UITableViewCell.appearance().selectedBackgroundView = colorView
to your viewDidLoad method.
But, it is ok only if you need not just green colour for selected cell, but something more complicated.
Better do this in your cellForRowAtIndexPath
cell.selectedColor = UIColor(red:0.31, green:0.62, blue:0.53, alpha:1.0)
If you just wanna change the background color, you don't need to create a UIView and set background color to it. instead change the contentView background and it should be in the didSelectRow... method. not in cellForRow.. as that is for the table view to load every single cell
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let green = UIColor(red:0.31, green:0.62, blue:0.53, alpha:1.0)
tableView.cellForRowAtIndexPath(indexPath)?.contentView.backgroundColor = green
}

How to change UITableView Cell text width in Swift

I'm trying to change the width of the of a cell's text in the UITableview
Which is taking the width of the container as I can see
var cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! UITableViewCell
cell.textLabel?.text = users[indexPath.row].User
cell.detailTextLabel?.text=String(users[indexPath.row].Score)
cell.textLabel?.bounds.width=20
I would like to show something like ( Truncate Tail):
I think screen short seems you reached the screen width already.so there is no use to increase Label width.If you want to show the full text your textLabel you can follow any one of the below solution.
cell.textLabel?.adjustsFontSizeToFitWidth = true;
it adjust the font size according to the Label width.
cell.textLabel?.numberOfLines = 0
it makes the Label text to display as two lines.
EDIT
if you want truncate tail for the textLabel try this.
cell.textLabel?.lineBreakMode = NSLineBreakMode.ByTruncatingTail
If you are using auto layout you could pin the number on the right to the right edge of the container view, place a horizontal spacer and give the name-label a lower compression resistance priority than the number label. This will make the name label as wide as possible but not so wide that it will clip into the number.
Actually, changing the frame of the textLabel in cell is NOT allowed in TableView. The width of frame for the textlabel of each cell relates to the cell, developer couldn't set it programmatically. However, I worked out a feasible solution: we may not change the frame of the textLabel, but we may change the source text alternatively. If we can truncate the source string in advance, this problem is overcome.
//Assign each element in the array a row in table view
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var myCell = myTableView.dequeueReusableCell(withIdentifier: "The Cell")
if myCell == nil {
myCell = UITableViewCell(style: UITableViewCellStyle.value1, reuseIdentifier: "The Cell")
}
myCell?.accessoryType = UITableViewCellAccessoryType.none
// If the text is too long (longer than 20 char), the text will be truncated
// The lenght of label cannot be set effectively here, so I truncate the source string alternatively
var myString: String = sectionArray[indexPath.section].items[indexPath.row]
if myString.characters.count > 20 {
let myIndex = myString.index(myString.startIndex, offsetBy: 20)
myString = myString.substring(to: myIndex)
myString += "..."
}
myCell?.textLabel?.text = myString
myCell?.detailTextLabel?.text = "\(NSDate())"
return myCell!
}
With this method, the effect of changing the textLabel's frame could be achieved.

Resources