在 iOS 的表格视图单元格中更改披露指示器附件视图的颜色/视图的最佳方法是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1852672/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:41:05  来源:igfitidea点击:

Which is the best way to change the color/view of disclosure indicator accessory view in a table view cell in iOS?

iosuitableviewindicatoraccessory

提问by AJ.

I need to change the color of the disclosureIndicatorViewaccessory in a UITableViewCell. I think there are two ways to get this done, but I'm not able to figure out which one's the optimum. So here is what I think I can do.

我需要disclosureIndicatorViewUITableViewCell. 我认为有两种方法可以完成这项工作,但我无法确定哪种方法是最佳的。所以这就是我认为我能做的。

There is a property of UITableViewCell- accessoryView. So I can use setAccessoryView:(UIView *)viewand pass view as the UIImageViewholding the image that I want.

有一个属性UITableViewCell- accessoryView。所以我可以使用setAccessoryView:(UIView *)view和传递视图作为UIImageView我想要的图像。

I have written an utility class which creates the content view (stuff like background color, adding other stuff, etc) for my cell and I add this content view to the cell in UITableViewDelegate. The other option is to draw a UIImageoverriding the drawRectmethod of CustomContentViewutility class.

我编写了一个实用程序类,它为我的单元格创建内容视图(如背景颜色、添加其他内容等),并将此内容视图添加到UITableViewDelegate. 另一种选择是绘制一个UIImage覆盖实用程序类的drawRect方法CustomContentView

Performing option 1 - I can get the things done the apple way. Just give them the view and they do the rest. But I guess adding a new UIViewobject to every row might turn out to be a heavy object allocation and decreasing the frame rate. As compared to just a UIImageobject in my contentView. I believe UIImageis lighter than UIView.

执行选项 1 - 我可以用苹果的方式完成工作。只给他们意见,他们做剩下的。但我想向UIView每一行添加一个新对象可能会导致大量对象分配并降低帧速率。与UIImage我的contentView. 我相信UIImageUIView.

Please throw some light people and help me decide over it.

请抛出一些轻松的人并帮助我决定它。

采纳答案by amrox

But I guess adding a new UIView object to every row might turn out to be a heavy obj allocation and decreasing the frame rate. As compared to just a UIImage object in my contentView. I believe UIImage is lighter than UIView.

但我想向每一行添加一个新的 UIView 对象可能会导致大量的 obj 分配并降低帧速率。与我的 contentView 中的 UIImage 对象相比。我相信 UIImage 比 UIView 轻。

Drawing an image directly will almost certainly have better performance than adding a subview. You have to determine if that extra performance is necessary. I've used a few accessory views for custom disclosure indicators on basic cells and performance was fine. However, if you're already doing custom drawing for the content rect, it might not be that difficult to do the accessory view also.

直接绘制图像几乎肯定会比添加子视图具有更好的性能。您必须确定是否需要额外的性能。我在基本单元格上使用了一些辅助视图来自定义披露指标,性能很好。但是,如果您已经在为内容矩形进行自定义绘图,那么制作附件视图也可能并不困难。

回答by Nate Potter

Great post on Cocoanetics that addresses this. The UIControl class inherits the properties selected, enabled and highlighted Custom-Colored Disclosure Indicators

Cocoanetics 上的好帖子解决了这个问题。UIControl 类继承了选择、启用和突出显示的属性Custom-Colored Disclosure Indicators

回答by benzado

If you're interested in drawing the indicator, instead of using an image file, here's code I worked out to do so:

如果您对绘制指标感兴趣,而不是使用图像文件,这里是我编写的代码:

// (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);

If you make a custom UIView subclass, do the above in the drawRect: method, and use that as your accessory view, you'll be able to make the color anything you want.

如果您创建自定义 UIView 子类,请在 drawRect: 方法中执行上述操作,并将其用作辅助视图,您将能够将颜色设置为您想要的任何颜色。

An accessory view (custom or UIImageView won't be a major performance problem as long as you are properly recycling UITableViewCell instances.

附件视图(自定义或 UIImageView 不会成为主要的性能问题,只要您正确回收 UITableViewCell 实例。

回答by gblazex

Here is an implementation that works in iOS 8+. It does exactly what's asked for:
change the color of the original Apple disclosure indicator to a custom color.
Use it like this:

这是一个适用于 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

UITableViewCell+DisclosureIndicatorColor.h

@interface UITableViewCell (DisclosureIndicatorColor)
@property (nonatomic, strong) UIColor *disclosureIndicatorColor;
- (void)updateDisclosureIndicatorColorToTintColor;
@end

UITableViewCell+DisclosureIndicatorColor.m

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

回答by Stephen Orr

In swift 3, I have adapted the solution from @galambalazs as a class extention as follows:

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

Hope this helps some.

希望这对一些人有所帮助。

回答by charliehorse55

Use an UIImageView. This will also allow you to change the image when the cell is selected:

使用 UIImageView。这也将允许您在选择单元格时更改图像:

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

回答by EeKay

benzado's solution works fine, but it showed a black background. In the UIView class that you setup (the one who's drawRect function you put in his code) needs to have the following initWithFrame implementation in order for the disclosure drawing to have a transparent background:

benzado 的解决方案工作正常,但它显示黑色背景。在您设置的 UIView 类中(您在代码中放置的 drawRect 函数)需要具有以下 initWithFrame 实现,以便公开绘图具有透明背景:

- (id)initWithFrame:(CGRect)frame {

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

Naturally, you can set this to whatever color you want...

当然,您可以将其设置为您想要的任何颜色......

回答by ymerej

While galambalazs' answer works, it should be noted that it is somewhat of a hack as it indirectly accesses and updates Apple's private implementation of the disclosure indicator. At best, it could stop working in future iOS releases, and at worst lead to App Store rejection. Setting the accessoryViewis still the approved method until Apple exposes a property for directly setting the color.

虽然 galambalazs 的回答有效,但应该注意的是,它在某种程度上是一种黑客行为,因为它间接访问和更新了 Apple 对披露指标的私有实现。充其量,它可能会在未来的 iOS 版本中停止工作,最坏的情况是导致 App Store 被拒绝。在accessoryViewApple 公开用于直接设置颜色的属性之前,设置仍然是批准的方法。

Regardless, here is the Swift implementation of his answer for those who may want it:

无论如何,这是他为可能需要的人提供的答案的 Swift 实现:

Note: cell.disclosureIndicatorColorhas to be set aftercell.accessoryType = .DisclosureIndicatoris set so that the disclosureIndicator button is available in the cell's subviews:

注意: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
    }
}

回答by Alex Chase

In iOS 13+ the disclosure indicator is set via a non-templeted UIImage, which is determined by the user's dark mode preference. Since the image is non-templated, it will not respect the cell's tintColor property. In other words, the dark mode preference has top priority. If you don't wan't to use the disclosure indicator derived by iOS, you will have to use a custom image.

在 iOS 13+ 中,披露指示符是通过非模板 UIImage 设置的,这由用户的暗模式偏好决定。由于图像是非模板化的,它不会考虑单元格的 tintColor 属性。换句话说,暗模式偏好具有最高优先级。如果您不想使用 iOS 派生的披露指示符,则必须使用自定义图像。

回答by Verticon

A swift 3 version of the CocoaNetics solution

CocoaNetics解决方案的swift 3 版本

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