ios uitableview indicator accessory

¿Cuál es la mejor manera de cambiar la vista de accesorios del indicador de divulgación de color/vista en una celda de vista de tabla en iOS?



uitableview indicator (11)

Necesito cambiar el color del accesorio disclosureIndicatorView en una UITableViewCell . Creo que hay dos formas de hacerlo, pero no puedo determinar cuál es el óptimo. Entonces, esto es lo que creo que puedo hacer.

Existe una propiedad de UITableViewCell - accessoryView . Entonces puedo usar setAccessoryView:(UIView *)view y pasar la vista como el UIImageView sosteniendo la imagen que quiero.

Escribí una clase de utilidad que crea la vista de contenido (cosas como el color de fondo, agregar otras cosas, etc.) para mi celda y agrego esta vista de contenido a la celda en UITableViewDelegate . La otra opción es dibujar un UIImage anulando el método drawRect de la clase de utilidad CustomContentView .

Ejecución de la opción 1: puedo hacer las cosas a la manera de la manzana. Solo denles la vista y ellos hacen el resto. Pero supongo que agregar un nuevo objeto UIView a cada fila podría ser una gran asignación de objetos y disminuir la velocidad de cuadros. En comparación con solo un objeto UIImage en mi contentView . Creo que UIImage es más ligero que UIView .

Por favor arroja a algunas personas ligeras y ayúdame a decidir sobre eso.


Pero supongo que agregar un nuevo objeto UIView a cada fila podría ser una gran asignación obj y una disminución de la velocidad de fotogramas. En comparación con solo un objeto UIImage en mi contentView. Creo que UIImage es más ligero que UIView.

Dibujar una imagen directamente seguramente tendrá un mejor rendimiento que agregar una subvista. Debe determinar si ese rendimiento adicional es necesario. Utilicé algunas vistas accesorias para indicadores de divulgación personalizados en células básicas y el rendimiento fue bueno. Sin embargo, si ya está haciendo un dibujo personalizado para el contenido rect, puede que no sea tan difícil hacer la vista accesoria también.


Aquí hay una implementación que funciona en iOS 8+. Hace exactamente lo que se solicita:
cambie el color del indicador de divulgación original de Apple a un color personalizado.
Úselo así:

#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


Como contribución a la solución de @benzado, aceleré su código de la siguiente manera:

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); }

Con un cambio del color de la aplicación, una llamada a setNeedsDisplay () en UITableCellView actualizará el color. Me gusta evitar el uso de objetos UIImage en vistas de celda.


En swift 3, he adaptado la solución de @galambalazs como una extensión de clase de la siguiente manera:

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 } } } } }

Espero que esto ayude a algunos.



La solución de Benzado funciona bien, pero mostró un fondo negro. En la clase UIView que configura (la que tiene la función drawRect que coloca en su código) necesita tener la siguiente implementación initWithFrame para que el dibujo de divulgación tenga un fondo transparente:

- (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self setBackgroundColor:[UIColor clearColor]]; // Initialization code. } return self; }

Naturalmente, puede configurar esto para el color que desee ...


Si bien la respuesta de galambalazs funciona, debe tenerse en cuenta que es algo así como un hack ya que accede indirectamente y actualiza la implementación privada de Apple del indicador de divulgación. En el mejor de los casos, podría dejar de funcionar en futuras versiones de iOS y, en el peor de los casos, provocar el rechazo de la App Store. Establecer el accessoryView sigue siendo el método aprobado hasta que Apple expone una propiedad para establecer directamente el color.

De todos modos, aquí está la implementación Swift de su respuesta para aquellos que lo deseen:

Nota: cell.disclosureIndicatorColor se debe configurar después de que cell.accessoryType = .DisclosureIndicator se configure de modo que el botón disclosureIndicator esté disponible en las subvistas de la celda:

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 } }


Si está interesado en dibujar el indicador, en lugar de usar un archivo de imagen, aquí está el código que resolví para hacerlo:

// (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 crea una subclase UIView personalizada, haga lo anterior en el método drawRect: y utilícela como su vista de accesorios, podrá hacer que el color sea el que desee.

Una vista de accesorio (personalizada o UIImageView no será un problema de rendimiento importante siempre que esté reciclando correctamente las instancias de UITableViewCell.


Una rápida versión 3 de la solution CocoaNetics

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() } } }


Use un UIImageView. Esto también le permitirá cambiar la imagen cuando se seleccione la celda:

UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage]; arrowView.highlightedImage = selectedImage; cell.accessoryView = arrowView; [arrowView release];


Ver una biblioteca muy fácilmente cambie los colores de todas las clases accessoryType.

MSCellAccessoryView