Qual é a melhor maneira de mudar a cor / vista do indicador de divulgação vista acessório em uma célula de exibição de tabela no iOS?
-
13-09-2019 - |
Pergunta
Eu preciso mudar a cor do acessório disclosureIndicatorView
em um UITableViewCell
.
Eu acho que existem duas maneiras de conseguir este feito, mas eu não sou capaz de descobrir qual é o ideal. Então aqui é o que eu acho que posso fazer.
Há uma propriedade de UITableViewCell
- accessoryView
. Então eu posso usar setAccessoryView:(UIView *)view
e passar vista como o UIImageView
segurando a imagem que eu quero.
Eu escrevi uma classe de utilitário que cria a exibição de conteúdo (coisas como cor de fundo, adicionando outras coisas, etc) para o meu celular e eu adicionar este ponto de vista de conteúdo para a célula em UITableViewDelegate
. A outra opção é chamar um UIImage
substituindo o método drawRect
de classe de utilitário CustomContentView
.
opção 1 Executar - eu posso conseguir as coisas feitas da maneira maçã. Basta dar-lhes a vista e eles fazem o resto. Mas eu acho que a adição de um novo objeto UIView
para cada linha pode vir a ser uma alocação objeto pesado e diminuir a taxa de quadros. Em comparação com apenas um objeto UIImage
na minha contentView
. Acredito UIImage
é mais leve que UIView
.
Por favor, jogue algumas pessoas leves e me ajudar a decidir sobre ele.
Solução
Mas eu acho que a adição de um novo objeto UIView para cada linha pode vir a ser uma alocação pesada obj e diminuindo a taxa de quadros. Em comparação com apenas um objeto UIImage no meu contentView. Acredito UIImage é mais leve que UIView.
Desenhar uma imagem diretamente quase certamente terá melhor desempenho do que a adição de um subexibição. Você tem que determinar se que o desempenho extra é necessário. Eu usei algumas vistas acessórias para os indicadores de divulgação personalizados em células básicas e desempenho estava bem. No entanto, se você já está fazendo desenho para o rect conteúdo personalizado, ele pode não ser tão difícil de fazer o ponto de vista acessório também.
Outras dicas
Great post sobre Cocoanetics que aborda esse. Os herda classe UIControl as propriedades seleccionadas, activado e destacada Custom-coloridos indicadores Divulgação
Se você está interessado em desenhar o indicador, em vez de usar um arquivo de imagem, código de aqui eu trabalhei para fazê-lo:
// (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);
Se você fizer uma subclasse UIView personalizado, faça o acima na drawRect: método, e usar isso como sua visão acessório, você vai ser capaz de fazer a cor que quiser
.Uma visão acessório (personalizado ou UIImageView não será um grande problema de desempenho, desde que você está reciclando adequadamente casos UITableViewCell.
Aqui está uma implementação que funciona em iOS 8+.
Ele faz exatamente o que é pedido para:
mudar a cor do indicador da Apple divulgação original para uma cor personalizada.
Usá-lo como este:
#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 rápida, que se adaptaram a solução de @galambalazs como uma extensão de classe como se segue:
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 isso ajude alguns.
Use um UIImageView. Isso também permitirá que você alterar a imagem quando a célula é selecionada:
UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage];
arrowView.highlightedImage = selectedImage;
cell.accessoryView = arrowView;
[arrowView release];
O benzado funciona bem, mas mostrou um fundo preto. Na classe UIView que você setup (o único que é drawRect função que você colocou no seu código) precisa ter a seguinte implementação initWithFrame para que a divulgação do desenho para ter um fundo transparente:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
// Initialization code.
}
return self;
}
Naturalmente, você pode definir isso ao que cor você quer ...
Enquanto obras resposta galambalazs, deve-se notar que é um pouco de um truque, uma vez que indiretamente acessa e atualiza implementação privada da Apple do indicador de divulgação. Na melhor das hipóteses, poderia parar de trabalhar no iOS futuros lançamentos, e na pior das hipóteses levar à rejeição App Store. Definir o accessoryView
ainda é o método aprovado até que a Apple expõe uma propriedade para definir directamente a cor.
De qualquer maneira, aqui é a implementação Swift de sua resposta para aqueles que podem querer isso:
Nota: cell.disclosureIndicatorColor
tem de ser definido após cell.accessoryType = .DisclosureIndicator
é definido para que o botão disclosureIndicator está disponível em subviews da 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 uma contribuição para a solução de @benzado I swiftified seu código como a seguir:
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);
}
Com uma mudança da cor aplicativo uma chamada para setNeedsDisplay () no UITableCellView irá atualizar a cor. Eu gostaria de evitar o uso de objetos UIImage em vista celulares.
Uma versão rápida 3 dos CocoaNetics solução
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()
}
}
}