Quelle est la meilleure façon de changer la couleur / vue de vue accessoire indicateur communication dans une cellule de vue de la table dans iOS?
-
13-09-2019 - |
Question
Je dois changer la couleur de l'accessoire de disclosureIndicatorView
dans un UITableViewCell
.
Je pense qu'il ya deux façons d'y parvenir, mais je ne suis pas en mesure de comprendre que l'on est l'optimum. Voici donc ce que je pense que je peux le faire.
Il y a une propriété de UITableViewCell
- accessoryView
. Je peux donc utiliser setAccessoryView:(UIView *)view
et passer vue comme UIImageView
tenant l'image que je veux.
J'ai écrit une classe utilitaire qui crée l'affichage du contenu (des choses comme la couleur d'arrière-plan, en ajoutant d'autres choses, etc) pour ma cellule et j'ajouter ce point de vue du contenu à la cellule dans UITableViewDelegate
. L'autre option consiste à dessiner un UIImage
remplaçant la méthode de drawRect
de classe utilitaire CustomContentView
.
Option Exécution 1 - je peux obtenir des choses fait le chemin de la pomme. Il suffit de leur donner la vue et ils font le reste. Mais je suppose que l'ajout d'un nouvel objet UIView
à chaque ligne pourrait se révéler une allocation d'objets lourds et en diminuant la vitesse de défilement. Par rapport à seulement un objet UIImage
dans mon contentView
. Je crois UIImage
est plus léger que UIView
.
S'il vous plaît jeter certaines personnes lumière et aidez-moi à décider dessus.
La solution
Mais je suppose que l'ajout d'un nouvel objet UIView à chaque ligne peut se révéler une allocation lourde obj et en diminuant la vitesse de défilement. Par rapport à seulement un objet UIImage dans mon contentView. Je crois UIImage est plus léger que UIView.
Dessiner une image directement aura certainement de meilleures performances que l'ajout d'un sous-vue. Vous devez déterminer si cette performance supplémentaire est nécessaire. Je l'ai utilisé quelques vues accessoires pour les indicateurs d'information personnalisés sur les cellules de base et la performance était bien. Toutefois, si vous faites déjà dessin personnalisé pour le rect contenu, il pourrait ne pas être si difficile à faire le point de vue accessoire aussi.
Autres conseils
Grande poste sur Cocoanetics qui traite de ce problème. La classe UIControl hérite des propriétés sélectionnées, activé et mis en évidence Indicateurs d'information sur mesure de couleur
Si vous êtes intéressé à tirer l'indicateur, au lieu d'utiliser un fichier image, voici le code que je travaille sur le faire:
// (x,y) is the tip of the arrow
CGFloat x = CGRectGetMaxX(self.bounds) - RIGHT_MARGIN;
CGFloat y = CGRectGetMidY(self.bounds);
const CGFloat R = 4.5;
CGContextRef ctxt = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(ctxt, x-R, y-R);
CGContextAddLineToPoint(ctxt, x, y);
CGContextAddLineToPoint(ctxt, x-R, y+R);
CGContextSetLineCap(ctxt, kCGLineCapSquare);
CGContextSetLineJoin(ctxt, kCGLineJoinMiter);
CGContextSetLineWidth(ctxt, 3);
// If the cell is highlighted (blue background) draw in white; otherwise gray
if (CONTROL_IS_HIGHLIGHTED) {
CGContextSetRGBStrokeColor(ctxt, 1, 1, 1, 1);
} else {
CGContextSetRGBStrokeColor(ctxt, 0.5, 0.5, 0.5, 1);
}
CGContextStrokePath(ctxt);
Si vous faites une sous-classe UIView personnalisée, faites ci-dessus dans la drawRect:. Méthode, et l'utiliser comme votre point de vue accessoire, vous serez en mesure de faire quoi que ce soit de la couleur que vous voulez
Une vue accessoire (sur mesure ou UIImageView ne sera pas un problème majeur de performance aussi longtemps que vous recyclez bien des cas UITableViewCell.
Voici une implémentation qui fonctionne dans iOS 8+.
Il fait exactement c'est demandé:
changer la couleur de l'indicateur d'information d'origine Apple à une couleur personnalisée.
Utilisez comme ceci:
#import "UITableViewCell+DisclosureIndicatorColor.h"
// cell is a UITableViewCell
cell.disclosureIndicatorColor = [UIColor redColor]; // custom color
[cell updateDisclosureIndicatorColorToTintColor]; // or use global tint color
UITableViewCell + DisclosureIndicatorColor.h
@interface UITableViewCell (DisclosureIndicatorColor)
@property (nonatomic, strong) UIColor *disclosureIndicatorColor;
- (void)updateDisclosureIndicatorColorToTintColor;
@end
UITableViewCell + DisclosureIndicatorColor.m
@implementation UITableViewCell (DisclosureIndicatorColor)
- (void)updateDisclosureIndicatorColorToTintColor {
[self setDisclosureIndicatorColor:self.window.tintColor];
}
- (void)setDisclosureIndicatorColor:(UIColor *)color {
NSAssert(self.accessoryType == UITableViewCellAccessoryDisclosureIndicator,
@"accessory type needs to be UITableViewCellAccessoryDisclosureIndicator");
UIButton *arrowButton = [self arrowButton];
UIImage *image = [arrowButton backgroundImageForState:UIControlStateNormal];
image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
arrowButton.tintColor = color;
[arrowButton setBackgroundImage:image forState:UIControlStateNormal];
}
- (UIColor *)disclosureIndicatorColor {
NSAssert(self.accessoryType == UITableViewCellAccessoryDisclosureIndicator,
@"accessory type needs to be UITableViewCellAccessoryDisclosureIndicator");
UIButton *arrowButton = [self arrowButton];
return arrowButton.tintColor;
}
- (UIButton *)arrowButton {
for (UIView *view in self.subviews)
if ([view isKindOfClass:[UIButton class]])
return (UIButton *)view;
return nil;
}
@end
3 rapide, j'ai adapté la solution de @galambalazs comme une extension de classe comme suit:
import UIKit
extension UITableViewCell {
func setDisclosure(toColour: UIColor) -> () {
for view in self.subviews {
if let disclosure = view as? UIButton {
if let image = disclosure.backgroundImage(for: .normal) {
let colouredImage = image.withRenderingMode(.alwaysTemplate);
disclosure.setImage(colouredImage, for: .normal)
disclosure.tintColor = toColour
}
}
}
}
}
Espérons que cela aide certains.
Utilisez un UIImageView. Cela vous permettra également de changer l'image lorsque la cellule est sélectionnée:
UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage];
arrowView.highlightedImage = selectedImage;
cell.accessoryView = arrowView;
[arrowView release];
La solution de benzado fonctionne très bien, mais il a montré un fond noir. Dans la classe UIView que vous configurez (celui qui est drawRect fonction que vous mettez dans son code) doit avoir la mise en œuvre initWithFrame suivante pour que la divulgation de dessin pour avoir un fond transparent:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
// Initialization code.
}
return self;
}
Bien sûr, vous pouvez mettre ce que la couleur que vous voulez ...
Alors que la réponse de galambalazs fonctionne, il convient de noter qu'il est un peu un hack car il accède indirectement et des mises à jour d'Apple mise en œuvre privée de l'indicateur de divulgation. Au mieux, il pourrait cesser de fonctionner dans les futurs iOS versions, et au pire entraîner le rejet App Store. Réglage de la accessoryView
est toujours la méthode approuvée jusqu'à ce qu'Apple expose une propriété pour la mise directement la couleur.
Peu importe, voici la mise en œuvre rapide de sa réponse pour ceux qui le veulent:
Remarque: cell.disclosureIndicatorColor
doit être réglé après cell.accessoryType = .DisclosureIndicator
est réglé de telle sorte que le bouton disclosureIndicator est disponible dans les sous-vues de la cellule:
extension UITableViewCell {
public var disclosureIndicatorColor: UIColor? {
get {
return arrowButton?.tintColor
}
set {
var image = arrowButton?.backgroundImageForState(.Normal)
image = image?.imageWithRenderingMode(.AlwaysTemplate)
arrowButton?.tintColor = newValue
arrowButton?.setBackgroundImage(image, forState: .Normal)
}
}
public func updateDisclosureIndicatorColorToTintColor() {
self.disclosureIndicatorColor = self.window?.tintColor
}
private var arrowButton: UIButton? {
var buttonView: UIButton?
self.subviews.forEach { (view) in
if view is UIButton {
buttonView = view as? UIButton
return
}
}
return buttonView
}
}
En tant que contribution à la solution de @benzado je swiftified son code comme suit:
override func drawRect(rect: CGRect) {
super.drawRect(rect)
let context = UIGraphicsGetCurrentContext();
let right_margin : CGFloat = 15.0
let length : CGFloat = 4.5;
// (x,y) is the tip of the arrow
let x = CGRectGetMaxX(self.bounds) - right_margin;
let y = CGRectGetMidY(self.bounds);
CGContextMoveToPoint(context, x - length, y - length);
CGContextAddLineToPoint(context, x, y);
CGContextAddLineToPoint(context, x - length, y + length);
CGContextSetLineCap(context, .Round);
CGContextSetLineJoin(context, .Miter);
CGContextSetLineWidth(context, 2.5);
if (self.highlighted)
{
CGContextSetStrokeColorWithColor(context, UIColor.appColorSelected().CGColor);
}
else
{
CGContextSetStrokeColorWithColor(context, UIColor.appColor().CGColor);
}
CGContextStrokePath(context);
}
Avec un changement de la couleur de l'application d'un appel à setNeedsDisplay () sur la UITableCellView mettra à jour la couleur. Je tiens à éviter l'utilisation d'objets UIImage dans les vues de cellules.
A rapide 3 version des CocoaNetics solution
public class DisclosureIndicator: UIControl {
public static func create(color: UIColor?, highlightedColor: UIColor?) -> DisclosureIndicator{
let indicator = DisclosureIndicator(frame: CGRect(x: 0, y: 0, width: 11, height: 15))
if let color = color { indicator.color = color }
if let color = highlightedColor { indicator.highlightedColor = color }
return indicator
}
public var color: UIColor = .black
public var highlightedColor: UIColor = .white
override public init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .clear
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
backgroundColor = .clear
}
override public func draw(_ rect: CGRect) {
super.draw(rect)
let context = UIGraphicsGetCurrentContext()!;
// (x,y) is the tip of the arrow
let x = self.bounds.maxX - 3.0;
let y = self.bounds.midY;
let length : CGFloat = 4.5;
context.move(to: CGPoint(x: x - length, y: y - length))
context.addLine(to: CGPoint(x: x, y: y))
context.addLine(to: CGPoint(x: x - length, y: y + length))
context.setLineCap(.round)
context.setLineJoin(.miter)
context.setLineWidth(3)
context.setStrokeColor((isHighlighted ? highlightedColor : color).cgColor)
context.strokePath()
}
override public var isHighlighted: Bool {
get {
return super.isHighlighted
}
set {
super.isHighlighted = newValue
setNeedsDisplay()
}
}
}