7

I am having a UIPicker, I want to change the color of the selector. Is it possible to change the color of the selector?

pasawaya
  • 11,515
  • 7
  • 53
  • 92
kiri
  • 1,977
  • 5
  • 27
  • 55
  • In case someone is looking for it, I added an answer for the Picker in SwiftUI here: https://stackoverflow.com/a/69944302/9497800 SwiftUI uses the UIPickerView behind the scenes and accessing its subviews, this line worked well for me: `picker.subviews[1].backgroundColor = UIColor.red` – multitudes Nov 12 '21 at 14:36

5 Answers5

23

Maybe it's not fully fits for answer to this question, in iOS 7 and later you can customize color by this way:

In the delegate methods

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component

add following

[[pickerView.subviews objectAtIndex:1] setBackgroundColor:NEEDED_COLOR];
[[pickerView.subviews objectAtIndex:2] setBackgroundColor:NEEDED_COLOR];

UPDATE

Previous code works, but so-so. Here simple subclasses for UIPickerView

Swift:

class RDPickerView: UIPickerView
{
    @IBInspectable var selectorColor: UIColor? = nil

    override func didAddSubview(subview: UIView) {
        super.didAddSubview(subview)
        if let color = selectorColor
        {
            if subview.bounds.height <= 1.0
            {
                subview.backgroundColor = color
            }
        }

    }
}

Objective-C:

@interface RDPickerView : UIPickerView

@property (strong, nonatomic) IBInspectable UIColor *selectorColor;

@end

@implementation RDPickerView

- (void)didAddSubview:(UIView *)subview
{
    [subview didAddSubview:subview];
    if (self.selectorColor)
    {
        if (subview.bounds.size.height <= 1.0)
        {
            subview.backgroundColor = self.selectorColor;
        }
    }
}

@end

and you can set selector color directly in storyboard

Thanks to Ross Barbish - "With iOS 9.2 and XCode 7.2 released 12/8/2015, the height of this selection view is 0.666666666666667".

UPDATE:

It's fix for issue with iOS 10, not good but works. :/

class RDPickerView: UIPickerView
{
    @IBInspectable var selectorColor: UIColor? = nil

    override func didAddSubview(_ subview: UIView) {
        super.didAddSubview(subview)

        guard let color = selectorColor else {
            return
        }

        if subview.bounds.height <= 1.0
        {
            subview.backgroundColor = color
        }
    }

    override func didMoveToWindow() {
        super.didMoveToWindow()

        guard let color = selectorColor else {
            return
        }

        for subview in subviews {
            if subview.bounds.height <= 1.0
            {
                subview.backgroundColor = color
            }
        }
    }
}

Thanks Dmitry Klochkov, I'll try to find some better solution.

vsilux
  • 790
  • 12
  • 14
  • This did work for me but there are not guarantees that this won't break in the future if Apple makes any changes to the pickerView. – Sid Nov 15 '14 at 23:19
  • Thank you! This is the ONLY real way to change the colors of the selection indicators. Works in swift. – ObjectiveTC Jul 31 '15 at 09:59
  • 1
    In iOS 9.2 I had to set subview.bounds.size.height <= 1.0 in order for the selection indicator bars to change color. – Nathan B. Mar 08 '16 at 01:28
  • On iOS 10 this works only the first time the view containing a picker is shown. When the view is shown second time the indicators color is back to default. – Dmitry Klochkov Nov 29 '16 at 12:52
  • @Dmitry Klochkov, I've added hotfix. – vsilux Nov 29 '16 at 13:53
  • Won't the app get rejected for accessing UIPickerView's subviews and directly modifying them? – Fengson Sep 27 '17 at 10:55
  • @Fengson No private API used here, so no problems with Apple review process. – vsilux Sep 28 '17 at 12:08
11

Here's an improvement to vsilux's answer, in form of a simple category to UIPickerView, without the need to subclass UIPickerView.

(Up-to-date answer as of November 2, 2018)

Swift 4, Xcode 10:

@IBInspectable var selectorColor: UIColor? {
    get {
        return objc_getAssociatedObject(self, &selectorColorAssociationKey) as? UIColor
    }
    set(newValue) {
        objc_setAssociatedObject(self, &selectorColorAssociationKey, newValue,
                                 objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
    }
}

open override func didAddSubview(_ subview: UIView) {

    super.didAddSubview(subview)
    if let color = selectorColor {
        if subview.bounds.height < 1.0 {
            subview.backgroundColor = color
        }
    }
}
BennyTheNerd
  • 3,930
  • 1
  • 21
  • 16
Ivan
  • 497
  • 4
  • 11
4

I suppose you're dealing with the iPhone SDK? There may be some other frameworks which uses this name, so maybe you can add your tags to include uikit, cocoa-touch or something.

Anyway, you can set showsSelectionIndicator of the UIPickerView instance to NO, so it hides the selector. Then you can create a new view with the adjusted selection style, and add it to the superview above the UIPickerView.

// Some sample code, but you can do this in IB if you want to
_pickerView = [[UIPickerView alloc] init];
_pickerView.showsSelectionIndicator = NO;
[_pickerView sizeToFit];
[self.view addSubview:_pickerView];

UIImage *selectorImage = [UIImage imageNamed:@"selectorImage.png"]; // You have to make it strechable, probably
UIView *customSelector = [[UIImageView alloc] initWithImage:selectorImage];
customSelector.frame = CGRectZero; // Whatever rect to match the UIImagePicker
[self.view addSubview:customSelector];
[customSelector release];

Hacking the UI Element itself will take much more work, and this has to work as well.

Joost
  • 10,333
  • 4
  • 55
  • 61
0

You can change just the selection indicator's background color as well.
Just add a UIView above the selection indicator (it will become your overlay view), set it's alpha value low(depends on you, but I like my overlay to look transparent), give it a background color and you are good to go.

Consider this,

var overlayOnPicker:UIView = UIView(frame: CGRectMake(1, 68, mypicker.frame.width, 26))
// Adds a layer on the selection indicator

And do put the CGRect's X value=1 (Remember, it's a frame, so it will be placed according to the superview's coordinate system)

overlayOnPicker.backgroundColor = UIColor.whiteColor()
overlayOnPicker.alpha = 0.2
myDatePicker.addSubview(overlayOnPicker)
// You have to add the overlayOnPicker view as a subview to the Date Picker.
// myDatePicker is the UIDatePicker that I declared earlier in my code
Zoran777
  • 564
  • 2
  • 7
  • 25
0

You can also subclass UIPickerView and add following customisations:

import UIKit

class CustomPickerView: UIPickerView {
    
    init() {
        super.init(frame: .zero)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        subviews.forEach { $0.backgroundColor = .clear }
    }
    
    override init(frame: CGRect) {
        fatalError("init(coder:) has not been implemented")
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
mazy
  • 652
  • 1
  • 10
  • 18