Change background of an Accessory View in a UITableViewCell - uitableview

According to Apple docs UITableViewCell consists of two sections:
I set a custom image for Accessory View:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("settingCell") as! SettingsTableViewCell
cell.setCellColor(self.items[indexPath.row])
let img = UIImage(named: "icon-right-arrow")!
let imgView:UIImageView = UIImageView()
imgView.contentMode = UIViewContentMode.ScaleAspectFill
imgView.frame.size.width = img.size.width
imgView.frame.size.height = img.size.height
imgView.image = img
imgView.image = imgView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
imgView.tintColor = UIColor.orangeColor()
cell.accessoryView = imgView
return cell
}
Function which get triggered when a cell is selected:
func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell = tableView.cellForRowAtIndexPath(indexPath) as! SettingsTableViewCell
selectedCell.setSelectedColor()
let img = UIImage(named: "icon-right-arrow")!
let imgView:UIImageView = UIImageView()
imgView.contentMode = UIViewContentMode.Center
imgView.frame.size.width = selectedCell.accessoryView!.frame.width
imgView.frame.size.height = selectedCell.accessoryView!.frame.height
imgView.backgroundColor = UIColor.orangeColor()
imgView.image = img
imgView.image = imgView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
imgView.tintColor = UIColor.whiteColor()
selectedCell.accessoryView = imgView
selectedCell.contentView.backgroundColor = UIColor.orangeColor()
}
And for deselected cell:
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell = tableView.cellForRowAtIndexPath(indexPath) as! SettingsTableViewCell
selectedCell.setDeSelectedColor()
let img = UIImage(named: "icon-right-arrow")!
let imgView:UIImageView = UIImageView()
imgView.contentMode = UIViewContentMode.Center
imgView.frame.size.width = selectedCell.accessoryView!.frame.width
imgView.frame.size.height = selectedCell.accessoryView!.frame.height
imgView.backgroundColor = UIColor.clearColor()
imgView.image = img
imgView.image = imgView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
imgView.tintColor = UIColor.orangeColor()
selectedCell.accessoryView = imgView
}
But the result is not what I want, Accessory View still has a gray background but I want it be orange:

you have to set deselected cell selectionStyle to None with UITableViewCellSelectionStyle.None
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
let selectedCell = tableView.cellForRowAtIndexPath(indexPath) as! SettingsTableViewCell
selectedCell.selectionStyle = UITableViewCellSelectionStyle.None
selectedCell.setDeSelectedColor()
let img = UIImage(named: "icon-right-arrow")!
let imgView:UIImageView = UIImageView()
imgView.contentMode = UIViewContentMode.Center
imgView.frame.size.width = selectedCell.accessoryView!.frame.width
imgView.frame.size.height = selectedCell.accessoryView!.frame.height
imgView.backgroundColor = UIColor.clearColor()
imgView.image = img
imgView.image = imgView.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate)
imgView.tintColor = UIColor.orangeColor()
selectedCell.accessoryView = imgView
}

Related

Elements of the FirstViewController still visible in DetailViewController after using pushViewController method

I first programmatically created a tableview :
private func setupTableView() {
tableView = UITableView(frame: CGRect(x: 0, y: 180, width: view.frame.width, height: view.frame.height), style: UITableView.Style.plain)
tableView.dataSource = self
tableView.delegate = self
tableView.register(ItemTableViewCell.self, forCellReuseIdentifier: "Cell")
view.addSubview(tableView)
}
and set the cellForRow method as below :
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ItemTableViewCell
guard let finalItems = presenter.finalItems?[indexPath.row] else { return cell }
presenter.configure(cell: cell, FinalItem: finalItems)
return cell
}
Then I configure the ItemTableViewCell as below :
class ItemTableViewCell: UITableViewCell {
private var iconImageView : UIImageView = {
let imgView = UIImageView(image: #imageLiteral(resourceName: "Image"))
imgView.contentMode = .scaleAspectFit
imgView.clipsToBounds = true
return imgView
}()
private var titleLabel : UILabel = {
let lbl = UILabel()
lbl.textColor = .black
lbl.font = UIFont.boldSystemFont(ofSize: 12)
lbl.textAlignment = .left
return lbl
}()
func configure(finalItem: FinalItem) {
titleLabel.text = finalItem.title
iconImageView.downloaded(from: finalItem.images_url.small)
}
}
When I push to the DetailViewController with the uinavigationbar, the elements contained in the rows (titles, labels...) are still visible a few milli seconds:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let finalItem = finalItems[indexPath.row]
let detailViewController = ModuleBuilder.createDetailModuleWith(finalItem)
detailViewController.finalItem = finalItem
navigationController?.pushViewController(detailViewController, animated: true)
}
This is not what I am expecting. I never figure this problem out before.

How to set fix ImageView size inside TableViewCell programmatically?

I have this issue wherein I need to fix the size on an image inside a tableviewcell. The image below shows that the image size in not uniform.
Here are the codes I used.
if noteImageIsAvailable == true {
if let imageData = assignedNotePhoto?.photoData {
if let image = Utilities.resizePictureImage(UIImage(data: imageData as Data)) {
//added fix
cell.imageView?.frame.size = CGSize(width: 36, height: 24)
cell.imageView?.clipsToBounds = true
//-----
cell.imageView?.contentMode = .scaleAspectFill
cell.imageView?.image = image
}
}
}
I read an answer here in stackoverflow. It says I need to add clipToBounds but unfortunately it doesn't work. Please help me solve this issue. Thank you
TableView Code
extension SettingNoteViewController: UITableViewDataSource, UITableViewDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return Menu.SettingNote.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = UITableViewCell(style: .subtitle, reuseIdentifier: "reuseIdentifier")
let keyPass = KeyHelper.NoteSetting.info[indexPath.row]
let assignedNotePhoto = self.getNotePhoto(key: keyPass.key)
let assignedNoteTextData = self.getNoteTextData(key: keyPass.key)?.value
cell.contentView.backgroundColor = .black
cell.textLabel?.textColor = .white
cell.detailTextLabel?.textColor = .white
cell.detailTextLabel?.numberOfLines = 0
let noteImageIsAvailable = assignedNotePhoto?.photoData != nil
if noteImageIsAvailable == true {
if let imageData = assignedNotePhoto?.photoData {
if let image = Utilities.resizePictureImage(UIImage(data: imageData as Data)) {
//added fix
cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
cell.imageView?.frame.size = CGSize(width: 36, height: 24)
cell.imageView?.clipsToBounds = true
//-----
cell.imageView?.contentMode = UIView.ContentMode.scaleAspectFit
cell.imageView?.image = image
}
}
}
cell.textLabel?.text = Menu.SettingNote.items[indexPath.row].value
cell.detailTextLabel?.text = assignedNoteTextData ?? "noteSettingSubTitle".localized
return cell
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.destination is InputMemoViewController {
let vc = segue.destination as! InputMemoViewController
vc.infoNoteKey = self.infoNoteKeyToPass
vc.infoLabelText = self.infoLabelToPass
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
self.infoNoteKeyToPass = KeyHelper.NoteSetting.info[indexPath.row].key
self.infoLabelToPass = KeyHelper.NoteSetting.info[indexPath.row].label
self.performSegue(withIdentifier: "showInputMemo", sender: self)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 80
}
}
The image below was the output when I applied #Kishan Bhatiya solution.
The first and second image is a landscape photo and the third image is in portrait
When you add cell.imageView?.translatesAutoresizingMaskIntoConstraints = false then frame has no effect, so try to use any one
let marginguide = contentView.layoutMarginsGuide
//imageView auto layout constraints
cell.imageView?.translatesAutoresizingMaskIntoConstraints = false
let marginguide = cell.contentView.layoutMarginsGuide
cell.imageView?.topAnchor.constraint(equalTo: marginguide.topAnchor).isActive = true
cell.imageView?.leadingAnchor.constraint(equalTo: marginguide.leadingAnchor).isActive = true
cell.imageView?.heightAnchor.constraint(equalToConstant: 40).isActive = true
cell.imageView?.widthAnchor.constraint(equalToConstant: 40).isActive = true
cell.imageView?.contentMode = .scaleAspectFill
cell.imageView?.layer.cornerRadius = 20 //half of your width or height
And it's better to set constraints in UITableViewCell
you know your imageview size. So you can resize your UIImage to imageView size.
extension UIImage{
func resizeImageWithHeight(newW: CGFloat, newH: CGFloat) -> UIImage? {
UIGraphicsBeginImageContext(CGSize(width: newW, height: newH))
self.draw(in: CGRect(x: 0, y: 0, width: newW, height: newH))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return newImage
}
}
use like that
let img = originalImage.resizeImageWithHeight(newW: 40, newH: 40)
cell.imageView?.image = img
Here, 40 40 is my imageview size
I have the same problem, scaleAspectFit is solved for me. you can try it
cell.imageView.contentMode = UIViewContentMode.scaleAspectFit

Circular Image in UITableViewCell

I'm trying to create circular Images inside of my TableViewCell but something is going wrong. I guess that the cornerRadius is to big because there is not any Image displayed with this Code. If I set the cornerRadius on 30 for example, I can see the Images rounded but not in a clear circle .Why is this not working ?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "QuestionLine")
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "QuestionLine")
let user = users[indexPath.row]
cell?.textLabel?.text = user.question
cell?.detailTextLabel?.text = user.name
let image = UIImage(named: user.profilePicture)
cell?.imageView?.image = image
cell?.imageView?.layer.cornerRadius = (image?.size.width)! / 2
cell?.imageView?.clipsToBounds = true
return cell!
}
The UITableViewCell's imageView will be sized to the height of the cell, If you want to customize the size of imageView try the below code.
let image = UIImage(named: user.profilePicture)
cell?.imageView?.image = image
let itemSize = CGSize.init(width: 40, height: 40) // your custom size
UIGraphicsBeginImageContextWithOptions(itemSize, false, UIScreen.main.scale);
let imageRect = CGRect.init(origin: CGPoint.zero, size: itemSize)
cell?.imageView?.image!.draw(in: imageRect)
cell?.imageView?.image! = UIGraphicsGetImageFromCurrentImageContext()!;
UIGraphicsEndImageContext()
cell?.imageView?.layer.cornerRadius = (itemSize.width) / 2
cell?.imageView?.clipsToBounds = true
Try this code
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "QuestionLine")
cell = UITableViewCell(style: .subtitle, reuseIdentifier: "QuestionLine")
let user = users[indexPath.row]
cell?.textLabel?.text = user.question
cell?.detailTextLabel?.text = user.name
let image = UIImage(named: user.profilePicture)
cell?.imageView?.image = image
cell?.imageView?.layer.cornerRadius = (cell?.imageView?.frame.size.width)! / 2
cell?.imageView?.layer.masksToBounds = true
cell?.imageView?.layer.borderColor = colour.cgColor
cell?.imageView?.layer.borderWidth = 1
return cell!
}
First make sure your image height and width is equal, then replace last 3 lines of code with these lines-
cell?.imageView?.layer.cornerRadius = (image?.frame.size.width)! / 2
cell?.imageView?.masksToBounds = true
return cell!

Swift - How to change the color of an accessoryType (disclosureIndicator)?

I have question about the accessoryType of cells. I am using a cell with an disclosureIndicator as accessoryType and I want to change it's color but I can't.
Does anyone know if this is a bug or if Apple forces me to use the grey color?
Actually I can change the colors of other accessoryType.
My code looks like this:
let cell = tableView.dequeueReusableCell(withIdentifier: "identifier", for: indexPath) as! customCell
cell.tintColor = UIColor.red
cell.accessoryType = .disclosureIndicator
And my arrow is still grey. But if I use a checkmark accessoryType it becomes red.
Is there any way to fix this or do I have to use a colored image?
You can do something like this
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.tintColor = UIColor.white
let image = UIImage(named: "Arrow.png")
let checkmark = UIImageView(frame:CGRect(x:0, y:0, width:(image?.size.width)!, height:(image?.size.height)!));
checkmark.image = image
cell.accessoryView = checkmark
let object = objects[indexPath.row] as! NSDate
cell.textLabel!.text = object.description
return cell
}
Sample Arrow Images
Output
Use SF Symbol
let image = UIImage(systemName: "chevron.right")
let accessory = UIImageView(frame:CGRect(x:0, y:0, width:(image?.size.width)!, height:(image?.size.height)!))
accessory.image = image
// set the color here
accessory.tintColor = UIColor.white
cell.accessoryView = accessory
Updated for Swift 4.2 with images attached:
cell.accessoryType = .disclosureIndicator
cell.tintColor = .black
let image = UIImage(named:"disclosureArrow")?.withRenderingMode(.alwaysTemplate)
if let width = image?.size.width, let height = image?.size.height {
let disclosureImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: width, height: height))
disclosureImageView.image = image
cell.accessoryView = disclosureImageView
}
Images you can use:
What it could look like:
Bellow Code is Swift 3.0 code, and will change the accessoryType color as per tintColor.
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.textLabel?.text = "SOME TITLE GOES HERE"
cell.accessoryType = .disclosureIndicator
cell.tintColor = UIColor.blue
let image = UIImage(named:"arrow1")?.withRenderingMode(.alwaysTemplate)
let checkmark = UIImageView(frame:CGRect(x:0, y:0, width:(image?.size.width)!, height:(image?.size.height)!));
checkmark.image = image
cell.accessoryView = checkmark
return cell
}
Swift 5. Extension style ;)
extension UITableViewCell {
func setupDisclosureIndicator() {
accessoryType = .disclosureIndicator
let imgView = UIImageView(frame: CGRect(x: 0, y: 0, width: 7, height: 12))
imgView.contentMode = .scaleAspectFit
imgView.image = UIImage(named: "your_icon_name")
accessoryView = imgView
}
}
Swift 5 & iOS 15 & Xcode 13
Here is an extension which uses SF Symbols, so you have a chevron like the default disclosure indicator one:
extension UITableViewCell {
func addCustomDisclosureIndicator(with color: UIColor) {
let button = UIButton(frame: CGRect(x: 0, y: 0, width: 10, height: 15))
let symbolConfig = UIImage.SymbolConfiguration(pointSize: 15, weight: .regular, scale: .large)
let symbolImage = UIImage(systemName: "chevron.right",
withConfiguration: symbolConfig)
button.setImage(symbolImage?.withTintColor(color, renderingMode: .alwaysOriginal), for: .normal)
button.tintColor = color
self.accessoryView = button
}
}
You can use it like this:
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
cell.addCustomDisclosureIndicator(with: .white) // Here your own color
return cell
}
Swift 5 & iOS 11-15
A combination of some answers
extension UITableViewCell {
func addCustomDisclosureIndicator(with color: UIColor) {
accessoryType = .disclosureIndicator
let disclosureImage = UIImage(named: "arrow_right")?.withRenderingMode(.alwaysTemplate)
let imageWidth = (disclosureImage?.size.width) ?? 7
let imageHeight = (disclosureImage?.size.height) ?? 12
let accessoryImageView = UIImageView(frame: CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight))
accessoryImageView.contentMode = .scaleAspectFit
accessoryImageView.image = disclosureImage
accessoryImageView.tintColor = color
accessoryView = accessoryImageView
}
}

Blur and vibrancy effects on UITableView

I just don't know how to do that. I've tried everything from Stackoverflow and nothing worked. I have a view, image and below all of that tableView in my hierarchy. But table view is still white. Is there somebody who knows how to do this? As I wrote, nothing from here worked.
I want to have this kind of UITableView:
Navigation bar is part of my question too (his blur and vibrancy).
After use of this code:
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
let backgroundImageView = UIImageView(image: UIImage(named: "background3.png"))
cell.backgroundView = backgroundImageView
var visualEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .Light)) as UIVisualEffectView
visualEffectView.frame = CGRectMake(0, 0, cell.bounds.width, cell.bounds.height)
backgroundImageView.addSubview(visualEffectView)
cell.textLabel?.text = self.field[indexPath.row]
cell.textLabel?.textColor = UIColor.whiteColor()
cell.textLabel?.backgroundColor = UIColor.clearColor()
return cell
}
My tableView now look like this:
And that is logical, because it is the look of the background3.png image.
Subclass UITableViewController.
let effect = UIBlurEffect(style: .Dark)
let resizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight
Build a background view like this and stick it into your table view. Notice separator effect, which is new api.
override func viewDidLoad() {
super.viewDidLoad()
let backgroundView = UIView(frame: view.bounds)
backgroundView.autoresizingMask = resizingMask
backgroundView.addSubview(self.buildImageView())
backgroundView.addSubview(self.buildBlurView())
tableView.backgroundView = backgroundView
tableView.separatorEffect = UIVibrancyEffect(forBlurEffect: effect)
}
func buildImageView() -> UIImageView {
let imageView = UIImageView(image: UIImage(named: "coolimage"))
imageView.frame = view.bounds
imageView.autoresizingMask = resizingMask
return imageView
}
func buildBlurView() -> UIVisualEffectView {
let blurView = UIVisualEffectView(effect: effect)
blurView.frame = view.bounds
blurView.autoresizingMask = resizingMask
return blurView
}
Change background colour of cell to clear, so background is visible when you have cells.
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)as! UITableViewCell
cell.backgroundColor = UIColor.clearColor()
return cell
}
So the solution is really simple. I've find a great tutorial on Youtube:
Swift iOS tutorial - Custom tableview appearance in Xcode 6
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
var openSansSemibold = UIFont(name: "OpenSans-Semibold", size: 12)?.fontDescriptor().fontDescriptorWithSymbolicTraits(UIFontDescriptorSymbolicTraits.TraitBold)
cell.textLabel?.font = UIFont(descriptor: openSansSemibold!, size: 12)
if(indexPath.row % 2 == 1){
cell.backgroundColor = UIColor.clearColor()
}else{
cell.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.2)
cell.textLabel?.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.0)
cell.detailTextLabel?.backgroundColor = UIColor.whiteColor().colorWithAlphaComponent(0.0)
}
cell.textLabel?.textColor = UIColor.whiteColor()
return cell
}
In viewDidLoad() method:
self.tableView.rowHeight = 70
self.tableView.backgroundView = UIImageView(image: UIImage(named: "background"))
And that is it. Every odd cell has clear color, every even has blurred background. It looks really great!

Resources