Cual es la mejor manera de cambiar el color/vista de la divulgación indicador de accesorios de ver en una vista de tabla de células en iOS?
-
13-09-2019 - |
Pregunta
Necesito cambiar el color de la disclosureIndicatorView
accesorio en un UITableViewCell
.Creo que hay dos maneras para hacer esto, pero no soy capaz de averiguar cuál es el óptimo.Así que aquí es lo que yo pienso hacer.
Hay una propiedad de UITableViewCell
- accessoryView
.Por lo tanto puedo usar setAccessoryView:(UIView *)view
y de paso ver como la UIImageView
la celebración de la imagen que quiero.
He escrito una clase de utilidad que crea la vista del contenido (cosas como el color de fondo, añadiendo otras cosas, etc) para mi celular y me agregue a esta vista del contenido de la celda en la UITableViewDelegate
.La otra opción es dibujar un UIImage
la invalidación de la drawRect
método de CustomContentView
utilidad de la clase.
La realización de la opción 1 - puedo conseguir el hacer las cosas de la forma en que apple.Sólo les dan la vista y ellos hacen el resto.Pero supongo que la adición de un nuevo UIView
objeto para cada fila puede llegar a ser un objeto pesado, la asignación y la disminución de la velocidad de fotogramas.En comparación a sólo una UIImage
objeto en mi contentView
.Creo UIImage
es más ligero que el UIView
.
Por favor, arrojar algo de luz a la gente y me ayude a decidir sobre él.
Solución
Pero supongo que la adición de un nuevo objeto UIView a cada fila podría llegar a ser una asignación obj pesada y la disminución de la velocidad de fotogramas. En comparación con sólo un objeto UIImage en mi contentView. Creo que es más ligero que UIImage UIView.
Dibujo una imagen directamente casi seguro que tienen un mejor rendimiento que la adición de una vista secundaria. Usted tiene que determinar si es necesario que el rendimiento adicional. He usado un par de puntos de vista de accesorios para indicadores de divulgación personalizados en las células básicas y el rendimiento estaba bien. Sin embargo, si ya está haciendo dibujo para el rect contenido personalizado, puede que no sea tan difícil de hacer la vista accesorio también.
Otros consejos
Gran post en Cocoanetics que se ocupa de esto. La clase uicontrol hereda las propiedades seleccionadas, habilitado y destacaron personalizada coloreadas
Si está interesado en la elaboración del indicador, en lugar de utilizar un archivo de imagen, aquí está el código que funcionó 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 usted hace una subclase UIView personalizado, haga lo anterior en el drawRect:. Método, y usar eso como su punto de vista accesorio, podrás hacer nada el color que desee
Una vista de accesorios (personalizado o UIImageView no será un problema mayor rendimiento siempre y cuando se está reciclando adecuadamente casos UITableViewCell.
Esta es una implementación que funciona en iOS 8 +.
Hace exactamente lo que ha pedido:
cambiar el color del indicador original divulgación de Apple a un color personalizado.
Utilizar de esta manera:
#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
en Swift 3, He adaptado la solución de @galambalazs como una extensión de la clase como sigue:
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 un poco.
Utilice un UIImageView. Esto también le permitirá cambiar la imagen cuando se selecciona la celda:
UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage];
arrowView.highlightedImage = selectedImage;
cell.accessoryView = arrowView;
[arrowView release];
La solución de benzado funciona bien, pero mostró un fondo negro. En la clase UIView que la configuración (el que está drawRect función se pone en su código) necesita tener la siguiente implementación initWithFrame a fin de que la divulgación de dibujo para tener un fondo transparente:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
// Initialization code.
}
return self;
}
Por supuesto, se puede establecer esto en cualquier color que desee ...
Mientras respuesta galambalazs' funciona, hay que señalar que se trata de algo así como un truco, ya que indirectamente accesos y actualizaciones de la aplicación privada de Apple en el indicador de la divulgación. A lo sumo, podría dejar de trabajar en las futuras versiones de iOS, y en el peor lugar al rechazo App Store. Ajuste de la accessoryView
sigue siendo el método aprobado hasta que Apple expone una propiedad para establecer directamente el color.
En cualquier caso, aquí es la rápida aplicación de su respuesta para aquellos que quieran que:
Nota: cell.disclosureIndicatorColor
tiene que ser establecido después cell.accessoryType = .DisclosureIndicator
se ajusta de manera que el botón disclosureIndicator está disponible en subvistas de la célula:
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
}
}
Como una contribución a la solución de @benzado I swiftified su código como sigue:
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 de color de la aplicación de una llamada a setNeedsDisplay () en el UITableCellView actualizará el color. Me gustaría evitar el uso de objetos en vistas UIImage celulares.
A SWIFT versión 3 de los CocoaNetics solución
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()
}
}
}