Каков наилучший способ изменить цвет/представление вида аксессуара индикатора раскрытия в ячейке представления таблицы в iOS?
Мне нужно изменить цвет аксессуара disclosureIndicatorView
в UITableViewCell
.
Я думаю, что есть два способа сделать это, но я не могу понять, какой из них оптимальный. Итак, вот что я думаю, что могу сделать.
Существует свойство UITableViewCell
- accessoryView
. Поэтому я могу использовать setAccessoryView:(UIView *)view
и просматривать представление как UIImageView
, удерживая изображение, которое я хочу.
Я написал класс утилиты, который создает представление содержимого (например, цвет фона, добавление другого материала и т.д.) для моей ячейки, и я добавляю этот просмотр содержимого в ячейку в UITableViewDelegate
. Другой вариант - сделать UIImage
переопределением метода drawRect
класса утилиты CustomContentView
.
Исполнение опции 1 - Я могу сделать все по-яблочному. Просто дайте им представление, и они сделают все остальное. Но я предполагаю, что добавление нового объекта UIView
к каждой строке может оказаться значительным распределением объектов и уменьшением частоты кадров. По сравнению с одним объектом UIImage
в моем contentView
. Я считаю, что UIImage
легче, чем UIView
.
Пожалуйста, бросьте некоторых светлых людей и помогите мне решить его.
Ответы
Ответ 1
Но я предполагаю, что добавление нового объекта UIView к каждой строке может оказаться тяжелым распределением obj и уменьшением частоты кадров. По сравнению с объектом UIImage в моем contentView. Я считаю, что UIImage легче UIView.
Рисование изображения напрямую почти наверняка будет иметь лучшую производительность, чем добавление subview. Вы должны определить, нужна ли дополнительная производительность. Я использовал несколько аксессуаров для пользовательских индикаторов раскрытия информации об основных ячейках, и производительность была прекрасной. Однако, если вы уже делаете пользовательский чертеж для прямоугольника содержимого, возможно, также сложно сделать аксессуар.
Ответ 2
Отличная статья о кокоенетике, которая решает эту проблему. Класс UIControl наследует выбранные, активированные и выделенные свойства индикаторы индикации цвета с индивидуальным цветом
Ответ 3
Если вам интересно рисовать индикатор, вместо использования файла изображения, здесь код, который я разработал, чтобы сделать это:
// (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);
Если вы создаете пользовательский подкласс UIView, сделайте это выше в методе drawRect: и используйте его в качестве дополнительного аксессуара, вы сможете сделать цвет тем, что хотите.
Вспомогательный вид (пользовательский или UIImageView не будет серьезной проблемой производительности, если вы правильно перерабатываете экземпляры UITableViewCell.
Ответ 4
Смотрите библиотеку. очень легко изменить цвета всех видов accessoriesType.
MSCellAccessoryView
Ответ 5
Вот реализация, которая работает в iOS 8+.
Он делает именно то, что просил:
измените цвет исходного индикатора Apple Apple на собственный цвет.
Используйте его так:
#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
Ответ 6
Используйте UIImageView. Это также позволит вам изменить изображение при выборе ячейки:
UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage];
arrowView.highlightedImage = selectedImage;
cell.accessoryView = arrowView;
[arrowView release];
Ответ 7
В swift 3 я адаптировал решение из @galambalazs как расширение класса следующим образом:
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
}
}
}
}
}
Надеюсь, это поможет некоторым.
Ответ 8
Решение бензадо прекрасно работает, но на черном фоне. В классе UIView, который вы настраиваете (тот, кто использует функцию drawRect, которую вы ввели в свой код), должен иметь следующую реализацию initWithFrame, чтобы рисунок раскрытия имел прозрачный фон:
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self setBackgroundColor:[UIColor clearColor]];
// Initialization code.
}
return self;
}
Естественно, вы можете установить это в любой цвет, который вы хотите...
Ответ 9
В то время как ответ galambalazs работает, следует отметить, что он является чем-то вроде взлома, поскольку он косвенно обращается и обновляет частную реализацию Apple индикатора раскрытия информации. В лучшем случае он может перестать работать в будущих выпусках iOS, а в худшем случае приведет к отказу App Store. Установка accessoryView
по-прежнему является утвержденным методом, пока Apple не предоставит свойство для непосредственной настройки цвета.
Несмотря на это, вот Быстрая реализация его ответа для тех, кто может этого захотеть:
Примечание. cell.disclosureIndicatorColor
должен быть установлен после установки cell.accessoryType = .DisclosureIndicator
, чтобы кнопка раскрытия информации отображалась в подзонах соты:
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
}
}
Ответ 10
В качестве вклада в решение @benzado я выполнил свой код следующим образом:
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);
}
При изменении цвета приложения вызов setNeedsDisplay() в UITableCellView обновит цвет. Мне нравится избегать использования объектов UIImage в представлениях ячеек.
Ответ 11
Быстрая версия 3 решения 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()
}
}
}