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

前端 未结 12 1907
有刺的猬
有刺的猬 2020-12-04 10:26

I need to change the color of the disclosureIndicatorView accessory in a UITableViewCell. I think there are two ways to get this done, but I\'m not

相关标签:
12条回答
  • 2020-12-04 10:35

    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.

    0 讨论(0)
  • 2020-12-04 10:39

    As a contribution to the solution of @benzado I swiftified his code as followed:

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

    With a change of the app color a call to setNeedsDisplay() on the UITableCellView will update the color. I like to avoid the use of UIImage objects in cell views.

    0 讨论(0)
  • 2020-12-04 10:41

    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.

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

    0 讨论(0)
  • 2020-12-04 10:41

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

    UIImageView* arrowView = [[UIImageView alloc] initWithImage:normalImage];
    arrowView.highlightedImage = selectedImage;
    cell.accessoryView = arrowView;
    [arrowView release];
    
    0 讨论(0)
  • 2020-12-04 10:49

    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 accessoryView is still the approved method until Apple exposes a property for directly setting the color.

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

    Note: cell.disclosureIndicatorColor has to be set after cell.accessoryType = .DisclosureIndicator is set so that the disclosureIndicator button is available in the cell's subviews:

    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 讨论(0)
  • 2020-12-04 10:55

    A swift 3 version of the 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()
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题