Swift: UIButton edgeinsets applies after cell redrawn/scroll - swift

after couple of days struggling I wanted to ask you about UIButton title and image edge insets...
I have custom cell with button and on that button depends on cell type should be different icons and text but the requirement text should be centered and image could be left aligned or right. For that I'm setting edge insets during updating button tile and image. To keep it simple I hard coded image insets left to be 8 and the calculating left point of title from which text should start.
func setTitleWithImage(_ title: String, imageName: String) {
self.btnStatus.setTitle(title, for: .normal)
self.btnStatus.setImage(UIImage(named: imageName), for: .normal)
self.btnStatus.imageEdgeInsets.left = 8
let btnWidth = btnStatus.frame.width
let titleLabelWidth = btnStatus.titleLabel?.frame.width
self.btnStatus.titleEdgeInsets.left = (btnWidth / 2) - (titleLabelWidth! / 2) - (btnStatus.imageView?.frame.width)! + self.btnStatus.imageEdgeInsets.left
}
The problem is that when tableview loaded it is wrong aligned but after scrolling/redraw cell it is aligned correctly. I tried different suggestions but no one helped me.
Before scroll
After scroll
To be more specific here the whole project.
Sources
UPDATED
ViewController almost all for more detailed please download sourrce
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 140
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = self.tableView.dequeueReusableCell(withIdentifier: "customCell", for: indexPath) as! CustomTableViewCell
cell.setTitleWithImage("DIFFERENT TEXT IS HERE ?", imageName: "icon")
cell.layoutIfNeeded()
cell.setNeedsLayout()
return cell
}

func alignTitleWithImageFrames () {
let btnWidth = btnStatus.frame.width
let titleLabelWidth = btnStatus.titleLabel?.frame.width
self.btnStatus.titleEdgeInsets.left = (btnWidth / 2) - (titleLabelWidth! / 2) - (btnStatus.imageView?.frame.width)! + 13
self.btnStatus.imageEdgeInsets.left = 8
}

Related

How to make optional images in a UITableViewCell?

Hi I'm making an app with UIkit and I'm having a problem trying to achieve the layout of a cell.
What I want is to make a cell that has an image header, a stack of user images, and a label. I place this cell in a UITableView. The problem I'm having is that the image header is optional so if it's not there I need it to display like the cell shown below in the attached image.
Can someone who has more knowledge in UIkit help me please?
let suppose you have struct that use to populate tableview
struct User {
let name:String
let headerImage:UIImage? // an optional image
}
your controller
class ViewController:UIViewController {
var users = [User]()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return users.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let image = users[indexPath.row].image {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserHeaderCell", for: indexPath) as! UserHeaderCell
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "UserSimpleCell", for: indexPath) as! UserSimpleCell
return cell
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if let image = users[indexPath.row].image {
return 100 // with image
}
return 50 // without image
}
}
make two cell one for header image and one for simple
class UserHeaderCell:UITableViewCell {
}
class UserSimpleCell:UITableViewCell {
}

Changing the height of cell depending on text height

I want to show a tableView with dynamic cell height. I found a way to change the height of my prototype cell in a tableView manually using this code. In this case the height is 400.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat (400)
}
In my cell the first part with the username (green and red) and the last part with the likes (yellow) has a fixed height with for example 60.
The height of the part in the middle (blue) should change depending on the text. So how can I do that?
I tried to get the label height with this.
override func awakeFromNib() {
super.awakeFromNib()
userComment.sizeToFit()
print(userComment.bounds.size.height)
}
But this always shows me 18. My aim is to use the first code above and return CGFloat ( 60 + 60 + dynamic label/userComment height)
This is how my tableView looks like.
extension ViewComments: UITableViewDataSource {
func tableView (_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return table.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
let video: importComment
video = table[indexPath.row]
cell.userName.text = video.userName
cell.userGroup.text = poiNavigationName.title
cell.userComment.text = video.userComment
cell.userTime.text = "\(video.userTime!)"
cell.userLikes.text = "\(video.userLikes!)"
cell.userName.text = video.userName
cell.commentId.text = video.commentId
cell.kommentarCount.text = "\(video.kommentarCount!)"
cell.buttonAction = { [unowned self] in
let selectedIndexPath = table[indexPath.row].commentId!
ViewComments.commentIDNew = selectedIndexPath
}
return cell
}
/*
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat (400)
}*/
}
Updated Picture after removing heightForRowAt and awakeFromNib
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return CGFloat (400)
}
instead of using a hard coded value you can use a dynamic height.
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
UITableView.automaticDimension
}
https://developer.apple.com/documentation/uikit/uitableview/1614961-automaticdimension
It seems to me you're describing something like this:
That's done entirely with the internal autolayout constraints of the prototype cell. You should not attempt to do this manually by returning a specific height for each cell; just let the runtime do it for you. It knows how to do this a lot better.
I solved it not following this tutorial and it works great. Tutorial

Swift4: How to change UITableView cell color

I have a UITable view where you can add items by pressing a button. I want its cells to be clear, I already made its background semitransparent, but once you click on the button that allows you to save the items in it, the first you save has a white background. Then, if you press the button other times, all of the cells, except for the last created, become semitransparent, but one continues to be white. This is my code, how could I make it completely clear?
extension ViewController : UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return number.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let textCell = tableView.dequeueReusableCell(withIdentifier: "WordCell", for: indexPath)
textCell.textLabel?.text = "\(indexPath.row + 1) \(number[indexPath.row])"
let semitransparentBlack = UIColor(rgb: 0x000000).withAlphaComponent(0.3)
textCell.layer.backgroundColor = semitransparentBlack.cgColor
textCell.textLabel?.layer.backgroundColor = semitransparentBlack.cgColor
textCell.textLabel?.textColor = UIColor.white
return textCell
}
}
You can set the color using textCell.backgroundColor = semitransparentBlack

Why is the width of cell in UItableview not same as width of screen in simulator?

The table cell is running shorter than it is supposed to be. (I use different background colour which shows difference width) The setting of cell is custom (only row height is change to 140). The playerCell class has nothing but some IBoutlets. Thanks.
(image: storyboard
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int
if playerBank.count == 0
{
count = 1
}
else{
count = playerBank.count
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! playerCell
if playerBank.isEmpty{
let p = Player()
playerBank = setInvalidPlayer(pBank: p, userInput: userInputPlayerName)
}
let playerInBank: Player = playerBank[indexPath.row]
passImageUrl = cell.setPlayerCell(p: playerInBank)
urlBank.append(passImageUrl)
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.red
cell.selectedBackgroundView = bgColorView
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ShowPlayerInfo", sender: self)
}
}
My first guess is that, while you have a custom cell with custom outlets, that there are no layout constraints in place. So the items that you put into the storyboard are retaining their intrinsic values and not adapting to the device screen size.
If you add constraints to those outlets, especially enough to where the width of the cell can be determined based on the rest of the elements, then your cell should display full width.

swift tableview image and label

I can't seem to figure how to have a tableview that contains a subject, body and image so that if there is not an image to have the subject and body together. see imageauto lay with table prototype
I would like the subject and body together when there is an image in the database and then if there is an image, then subject image body
pin the labels to the top and bottom of the cell. When you don't have an image you set the imageView.isHidden = true. You also return the regular cell height minus the imageView.frame.size.height in UITableViewDelegate.tableview(_:heightForRowAt:).
If you don't like approach just make two different tableViewCells and deque the one with the image when you have an image and the one without the imageView when you don't have an image.
You can do this in your dataSource methods for the tableview. Something like this should work:
//Model:
var model = [Stuff]
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myprototype", for: indexPath)
cell.subjectLabel.text = model[indexPath.row].subject
cell.bodyLabel.text = model[indexPath.row].body
//assuming the image is an optional
if let image = model[indexPath.row].image {
cell.imageView.image = image
}
return cell
}
You might have to set the autolayout constraints for the imageView to have a low compression resistance.
You might also want to make the cells resize by implementing the following in the UITableViewDelegate methods:
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}