【问题标题】:Which is the best way to change the color/view of disclosure indicator accessory view in a table view cell in iOS?在 iOS 的表格视图单元格中更改披露指示器附件视图的颜色/视图的最佳方法是什么?
【发布时间】:2019-12-04 18:08:00
【问题描述】:

我需要更改UITableViewCelldisclosureIndicatorView 附件的颜色。 我认为有两种方法可以完成这项工作,但我无法确定哪种方法是最佳的。所以这就是我认为我能做的。

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

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

执行选项 1 - 我可以按照苹果的方式完成工作。只需给他们视图,其余的由他们完成。但我想每行添加一个新的UIView 对象可能会导致对象分配繁重并降低帧速率。与我的 contentView 中的 UIImage 对象相比。我相信UIImageUIView 轻。

请扔一些轻松的人,帮我做决定。

【问题讨论】:

标签: ios uitableview indicator accessory


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    如果您对绘制指标感兴趣,而不是使用图像文件,请使用以下代码:

    // (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 实例。

    【讨论】:

    • 你能告诉我如何设置 CONTROL_IS_HIGHLIGHTED 吗?我的意思是,单元格如何知道它已突出显示?
    • 如果你在表格视图单元格上绘图,我很确定 UITableViewCell 有一个highlighted 属性。
    • 我一直在尝试使用此代码,但由于某种原因,我失去了两条线相交的锐点并获得了一个柔和的角度,有什么想法吗?
    • CGContextSetLineJoin() 控制此时发生的事情。也许你把它漏掉了?还是你调用它一次,然后绘制改变当前行连接设置的其他东西?
    • @VanDuTran 是的,这只是绘制代码,这些 API 都没有改变。
    【解决方案3】:

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

    【讨论】:

    • 红变蓝
    【解决方案4】:

    在 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】:

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

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

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

          【解决方案7】:

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

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

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

          【讨论】:

            【解决方案8】:

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

            无论如何,对于那些可能想要它的人来说,这是他的答案的 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
                }
            }
            

            【讨论】:

            • Apple 从未禁止访问视图层次结构。通常是私有 API(文档中未包含的方法、属性或类)让您破产。
            • 这不仅仅是访问视图层次结构,它还通过层次结构间接检索私有 UIButton 属性并对其进行修改。
            【解决方案9】:

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

            【讨论】:

              【解决方案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);
              }
              

              随着应用程序颜色的更改,对 UITableCellView 上的 setNeedsDisplay() 的调用将更新颜色。我喜欢避免在单元格视图中使用 UIImage 对象。

              【讨论】:

                【解决方案11】:

                一个 Swift 3 版本的 CocoaNetics solution

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

                【讨论】:

                  【解决方案12】:

                  更改表格视图单元格的色调颜色。 通过 Storyboard 检查屏幕截图以执行相同操作。

                  【讨论】:

                  • 这个答案是有条件的。复选标记附件尊重单元格的色调,但是,披露指示符(此特定问题中指定的属性)没有。
                  猜你喜欢
                  • 1970-01-01
                  • 2012-07-09
                  • 2018-10-20
                  • 2011-04-27
                  • 1970-01-01
                  • 2018-10-04
                  • 2010-09-07
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多