18

My app has a tableview with an image and a textfield:

  • image = image render as template image (light grey)
  • textfield = text color black

If I select a row, the color of both will change perfectly to white

Question - I change the image to a blue color image = render as default. If I now select a row, the text color of my textfield will change to white, but the image will stay blue.

I want the image change the color to white too but it doesn't.

What did I do wrong?

Example with an image render as template mode => default: grey | selected automatically white

enter image description here

Example with an colored image render as default mode => default: green | selected also green | expected white, but it stay green

enter image description here

Trombone0904
  • 4,132
  • 8
  • 51
  • 104

3 Answers3

2

Try this:

    import Cocoa

class ViewController: NSViewController {
    @IBOutlet weak var tableView:NSTableView!
    var selectIndex = -1
    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.delegate = self
        self.tableView.dataSource = self

    }

    func tintedImage(_ image: NSImage, tint: NSColor) -> NSImage {
        guard let tinted = image.copy() as? NSImage else { return image }
        tinted.lockFocus()
        tint.set()

        let imageRect = NSRect(origin: NSZeroPoint, size: image.size)
        NSRectFillUsingOperation(imageRect, .sourceAtop)

        tinted.unlockFocus()
        return tinted
    }
}

extension ViewController:NSTableViewDataSource, NSTableViewDelegate{
    func numberOfRows(in tableView: NSTableView) -> Int {
        return 3
    }

    func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView?{


        let result = tableView.make(withIdentifier: "imageIcon", owner: self) as! NSTableCellView
        if selectIndex == row{
            result.imageView?.image = self.tintedImage(NSImage(named:"file")!, tint: NSColor.green)

        }else{
            result.imageView?.image = self.tintedImage(NSImage(named:"file")!, tint: NSColor.gray)

        }
        return result

    }

    func tableView(_ tableView: NSTableView, didAdd rowView: NSTableRowView, forRow row: Int) {
        if selectIndex == row{
            rowView.backgroundColor = NSColor.blue
        }else{
            rowView.backgroundColor = NSColor.clear
        }
    }


    func tableViewSelectionDidChange(_ notification: Notification) {
        let table = notification.object as! NSTableView
        self.selectIndex = tableView.selectedRow

        print(table.selectedRow);
        table.reloadData()
    }
}

Note: Change imageView tintColor color as per your requirement.

table row selection with color
Hope it will help you.

Yuyutsu
  • 2,509
  • 22
  • 38
  • i need a osx solution :( – Trombone0904 Sep 11 '17 at 05:32
  • unbelievable that a osx solution is so complicated. in iOS it is much easier :/ – Trombone0904 Sep 11 '17 at 12:54
  • Have you tried? Let me know if it is working or not. – Yuyutsu Sep 12 '17 at 07:41
  • yea i tried this a few days ago. this solution i found also on stack overflow. but i can't believe hat this have to be so much complicated. and i guess hat your code `tableViewSelectionDidChange` doesn't work. i tried this and if i put my `outlineView.reloadData()` in this function, the selection will always change by calling reloadData => loop :( – Trombone0904 Sep 12 '17 at 07:46
  • @Ghost108 Don't call `reloadData`, check the documentation for a method to reload one cell. – Willeke Sep 13 '17 at 11:36
  • Instead of `reloadData`, in `tableViewSelectionDidChange` use [`enumerateAvailableRowViewsUsingBlock:`](https://developer.apple.com/documentation/appkit/nstableview/1532750-enumerateavailablerowviewsusingb) which operates only on the currently needed rows, not all, and is thus quite performant. – RHB Aug 29 '22 at 17:40
2

Create a custom cell and override the setHighlighted(_ highlighted: Bool, animated: Bool) to change the iamgeView's tintColor :

override func setHighlighted(_ highlighted: Bool, animated: Bool) {
    super.setHighlighted(highlighted, animated: animated)
    imageView?.tintColor = highlighted ? UIColor.white : UIColor.green
}

Then, when you create your cell, you set the image with an UIImageRenderingMode.alwaysTemplate:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = CustomCell()
    cell.imageView?.image = UIImage(named: "custom_image")?.withRenderingMode(UIImageRenderingMode.alwaysTemplate)
    cell.imageView?.tintColor = UIColor.green
    return cell
}
Bessi
  • 161
  • 1
  • 4
2

Better late than never.

Here's my solution which a friend helped me with. Implement a custom NSImageCell class and override interiorBackgroundStyle:

#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN

@interface TFSelectStateImageCell : NSImageCell

@end

NS_ASSUME_NONNULL_END
#import "TFSelectStateImageCell.h"

@implementation TFSelectStateImageCell


- (NSBackgroundStyle)interiorBackgroundStyle {
    NSBackgroundStyle style = [super interiorBackgroundStyle];
    self.image.template = (style == NSBackgroundStyleEmphasized);
    return style;
}

@end

This way you get the benefits of the template property for an NSImage when the row is selected, but when it's not selected, you get your full colour image.

Tap Forms
  • 912
  • 8
  • 16
  • I could kiss you, my friend ... I was really struggling with this problem, and you saved the day :) Upvoted ... this should be the accepted answer. – waldenCalms Apr 23 '22 at 18:56
  • 1
    Yup. it's a very simple solution, but something that's not so obvious. – Tap Forms Apr 24 '22 at 08:16