Каков наилучший способ изменить цвет / представление вспомогательного представления индикатора раскрытия в ячейке табличного представления в iOS? - PullRequest
21 голосов
/ 05 декабря 2009

Мне нужно изменить цвет аксессуара disclosureIndicatorView в UITableViewCell. Я думаю, что есть два способа сделать это, но я не могу понять, какой из них оптимален. Вот что я думаю, что могу сделать.

Существует свойство UITableViewCell - accessoryView. Поэтому я могу использовать setAccessoryView:(UIView *)view и передать представление как UIImageView, содержащее нужное мне изображение.

Я написал служебный класс, который создает представление содержимого (например, цвет фона, добавление других элементов и т. Д.) Для моей ячейки, и я добавляю это представление содержимого в ячейку в UITableViewDelegate. Другой вариант - нарисовать UIImage, переопределяющий метод drawRect служебного класса CustomContentView.

Выполнение варианта 1 - я могу сделать все по-яблочному. Просто дайте им представление, а они сделают все остальное. Но я думаю, что добавление нового объекта UIView в каждую строку может оказаться тяжелым распределением объектов и уменьшением частоты кадров. По сравнению с просто UIImage объектом в моем contentView. Я считаю, что UIImage легче, чем UIView.

Пожалуйста, бросьте несколько легких людей и помогите мне решить это.

Ответы [ 11 ]

29 голосов
/ 05 апреля 2011

Отличный пост по Кокоанетике, посвященный этому. Класс UIControl наследует выбранные, включенные и выделенные свойства Пользовательские индикаторы раскрытия

24 голосов
/ 04 января 2010

Если вы заинтересованы в рисовании индикатора, вместо использования файла изображения, вот код, который я разработал для этого:

// (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.

10 голосов
/ 16 февраля 2016

Вот реализация, которая работает в iOS 8+. Это именно то, что просили:
изменить цвет исходного индикатора раскрытия 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
7 голосов
/ 27 февраля 2017

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

Надеюсь, это поможет некоторым.

5 голосов
/ 06 июля 2012

Используйте UIImageView. Это также позволит вам изменить изображение при выборе ячейки:

UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage];
arrowView.highlightedImage = selectedImage;
cell.accessoryView = arrowView;
[arrowView release];
4 голосов
/ 06 декабря 2009

Но я полагаю, что добавление нового объекта UIView в каждую строку может привести к значительному выделению объектов и снижению частоты кадров. По сравнению с просто объектом UIImage в моем contentView. Я считаю, что UIImage легче, чем UIView.

Рисование изображения напрямую почти наверняка будет иметь лучшую производительность, чем добавление подпредставления. Вы должны определить, необходима ли эта дополнительная производительность. Я использовал несколько дополнительных представлений для пользовательских индикаторов раскрытия информации о базовых ячейках, и производительность была в порядке. Однако, если вы уже делаете пользовательское рисование для прямоугольника содержимого, это может быть не так сложно сделать вспомогательный вид.

2 голосов
/ 12 января 2011

Решение Бензадо работает нормально, но оно показало черный фон. В классе UIView, который вы настраиваете (тот, кто использует функцию drawRect, которую вы поместили в его код), должен иметь следующую реализацию initWithFrame, чтобы чертеж раскрытия имел прозрачный фон:

- (id)initWithFrame:(CGRect)frame {

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

Естественно, вы можете установить любой цвет по своему желанию ...

1 голос
/ 08 ноября 2018

Изменить цвет оттенка ячейки табличного представления. Проверьте скриншот, чтобы сделать то же самое через раскадровку.

1 голос
/ 06 апреля 2016

Хотя ответ галамбалаза работает, следует отметить, что это своего рода хак, поскольку он косвенно обращается к частной реализации индикатора раскрытия информации Apple и обновляет ее. В лучшем случае он может перестать работать в будущих выпусках iOS, а в худшем - привести к отказу от App Store. Установка accessoryView по-прежнему является утвержденным методом, пока Apple не предоставит свойство для прямой настройки цвета.

Независимо, вот реализация Swift его ответа для тех, кто может хотеть этого:

Примечание: cell.disclosureIndicatorColor должно быть установлено после того, как cell.accessoryType = .DisclosureIndicator установлено так, чтобы кнопка 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
    }
}
0 голосов
/ 31 июля 2017

Быстрая 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()
        }
    }
}
...