skip to Main Content

In a UICollectionView within a UISplitViewController layout, I have a UICollectionView.CellRegistration that shows under certain conditions a warning badge as UICellAccessory.

This warning badge accessory is based on the following code:

func warningBadge(cell: UICollectionViewListCell) -> UICellAccessory  {

    return UICellAccessory.customView(configuration: 
    .init(customView: UIImageView(image: UIImage(systemName: "exclamationmark.triangle")), 
           placement: .trailing(),
 reservedLayoutWidth: .custom(18), 
           tintColor: UIColor(dynamicProvider: { collection in

        if cell.isSelected {
            return .lightText
        }
        else {
            return .systemRed
        }
    })))
}

This works fine, except when the focus in the app moves to another part in the Split View control.

In that case the selected cell show a light grey background, instead of a tintColor background (which is correct), but the warning badge still has a selected appearance, which makes it hard to see (lightText on top of light grey background).

In case when the cell is selected but not focused, the image should have the non selected tintColor (.systemRed in this example code).

I tried to use cell.isFocused instead of, or in addition to cell.isSelected, but this doesn’t work.

Interestingly, cell.isFocused does work correctly for UICellAccessory.label accessories, but apparently not for a UICellAccessory.customView with an image control.

How to give a custom accessory the correct tintColor when the cell is selected, but not focused?

2

Answers


  1. Chosen as BEST ANSWER

    The solution turned out to make a custom view based on UILabel instead of UIImageView. Normally you don't need a custom view for a label accessory, but I already have a UICellAccessory.label in my cell registration, and you're not allowed to use system accessory twice.

    This is the working code I now use:

    func warningBadge(cell: UICollectionViewListCell) -> UICellAccessory  {
        let label = UILabel()
        let attachment = NSTextAttachment()
        attachment.image = UIImage(systemName: "exclamationmark.triangle")?.withTintColor( UIColor(dynamicProvider: { collection in
            return cell.isFocused ? .lightText : .systemRed
        }))
        label.attributedText = NSAttributedString(attachment: attachment)
        return UICellAccessory.customView(configuration: .init(customView: label, placement: .trailing(), reservedLayoutWidth: .custom(18)))
    }
    

  2. The issue here is that the custom accessory retains its appearance even when the cell is selected but not focused. To address this, you can employ the following approach:

    Instead of relying solely on cell.isSelected, you can also utilize cell.isFocused to correctly set the tintColor for the image in the custom accessory. However, as you’ve noted, cell.isFocused seems not to work for UICellAccessory.customView with an image control.

    To tackle this issue, you can wrap your custom UIImageView within a UIView and then set the tintColor for that UIView. This will enable you to correctly set the tintColor based on the cell’s state.

    Here’s how you can implement it:

    func warningBadge(cell: UICollectionViewListCell) -> UICellAccessory  {
        let imageView = UIImageView(image: UIImage(systemName: "exclamationmark.triangle"))
        imageView.tintColor = cell.isSelected ? .lightText : .systemRed
        
        let containerView = UIView()
        containerView.addSubview(imageView)
        
        // Set desired constraints for imageView here if necessary
        // For example:
        // imageView.translatesAutoresizingMaskIntoConstraints = false
        // imageView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
        // imageView.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true
        
        return UICellAccessory.customView(configuration: .init(customView: containerView, reservedLayoutWidth: .custom(18)))
    }
    

    This should allow you to correctly set the tintColor for your image in the custom accessory based on the cell’s state, regardless of whether it’s focused or not.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search