38

So I have a uipickerview with rows that only contain the number 0-24 and it looks a bit silly since the numbers are left aligned leaving a huge gap on the right of the pickerview.

Is there an easy way to center align text in a uipickerview?

Msencenb
  • 5,675
  • 11
  • 52
  • 84
  • 1
    It will still look silly if the numbers are centered. What are the numbers? Why not write for example "24 hours" instead of "24". It may be redundant but it looks better. – Matthias Bauch Feb 18 '11 at 08:23
  • @fluchtpunkt Actually a good idea.. it does look quite a bit better – Msencenb Feb 18 '11 at 17:53

9 Answers9

70
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 37)];
    label.text = [NSString stringWithFormat:@"something here"];
    label.textAlignment = NSTextAlignmentCenter; //Changed to NS as UI is deprecated.
    label.backgroundColor = [UIColor clearColor];
    [label autorelease];
    return label;
}

or something like this.

Robin
  • 10,011
  • 5
  • 49
  • 75
  • 1
    I also use this to change the font color based on which row it is, like this: if (row == 0) { [label setTextColor:[UIColor redColor]]; } else { [label setTextColor:[UIColor darkTextColor]]; } – Structurer Oct 17 '12 at 10:51
  • 1
    By default the text in a UIPicker is bold. With this approach you should add the line `label.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]];` to get a similar appearance. – To1ne Feb 21 '13 at 12:55
  • 3
    Good, but should be reusing the view instead of creating a new label on every invocation. – wcochran Mar 12 '13 at 17:13
  • 1
    You can update your code with this to be conform to iOS7 : [label setTextAlignment:NSTextAlignmentCenter]; or label.textAlignment = NSTextAlignmentCenter; – DjimOnDev Apr 28 '14 at 10:00
22

A little easier now in iOS 6... There's a new method you can implement to return an attributed string... And you can define alignment in attributed strings.

- (NSAttributedString *)pickerView:(UIPickerView *)pickerView attributedTitleForRow:(NSInteger)row forComponent:(NSInteger)component {
    NSString *text = [NSString stringWithFormat:@"R%d C%d", row, component];
    NSMutableAttributedString *as = [[NSMutableAttributedString alloc] initWithString:text];
    NSMutableParagraphStyle *mutParaStyle=[[NSMutableParagraphStyle alloc] init];
    mutParaStyle.alignment = NSTextAlignmentCenter;
    [as addAttribute:NSParagraphStyleAttributeName value:mutParaStyle range:NSMakeRange(0,[text length])];
    return as;
}
James Boutcher
  • 2,593
  • 1
  • 25
  • 37
  • Thanks, this works, but dang is it a PitA. Also it's worth noting that this is going to replace whatever is being returned from `pickerView:titleForRow:forComponent:`. What I did was just copy my code from that method, and replace my `return`s with `text =`, and that seems to be working. – GeneralMike Sep 06 '13 at 13:49
13

You can implement this delegate method, which returns a CGFloat

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component

This is called on the picker view to determine row width.

Rog
  • 18,602
  • 6
  • 76
  • 97
  • 1
    I actually did use this technique to make the picker smaller... I think it looks better than just centering. That being said I'm going to mark the uiview subclass as teh correct answer since the original title was about centering in a UIPickerView... but you're answer is very helpful too. Upvoted. – Msencenb Feb 18 '11 at 17:54
  • Thank you so much for this tip! It turns out that iOS 7 will disregard `widthForComponent` if you set the pickerview frame after `viewDidLoad`. iOS 6, OTOH, will partly resize (see http://i.imgur.com/UDLaDYO.png) the pickerview according to `widthForComponent`, and partly according to the view frame. My solution was to not implement `widthForComponent`, only set the pickerview frame. – thomax Apr 15 '14 at 11:01
5

Below one also working fine -

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
    UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, [pickerView rowSizeForComponent:component].width, [pickerView rowSizeForComponent:component].height)];
    lbl.text = [reservePickerArray objectAtIndex:row];
    lbl.adjustsFontSizeToFitWidth = YES;
    lbl.textAlignment=UITextAlignmentCenter;
    lbl.font=[UIFont systemFontOfSize:20];
    return lbl;
}

Cheers!!

Praveenkumar
  • 24,084
  • 23
  • 95
  • 173
3

Remember, the view in

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

is actually a UITableViewCell, so you can work with it like:

- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
    static NSString *cellIdentifier = @"pickerViewCell";
    UITableViewCell *cell = (UITableViewCell*)view;

    if(cell==nil)
    {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
        /** customize the cell **/
    }

    /** set the label **/
    cell.textLabel.text = [dataSource objectAtIndex:row];

    return cell;
}
Farhad Malekpour
  • 1,314
  • 13
  • 16
  • 2
    With that delegate method you can return any UIView you like. In the accepted answer it is suggested to use a simple UILabel and set the text alignment to center. That works. But if you want something different like a list of minutes in a centered column, but so their right edges line up (not just simply centered), then a UITableViewCell laid out to your liking is an excellent suggestion. +1 – Craig B Aug 24 '12 at 17:16
1

Just set the width to the width of the view and the text will center automatically:

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component {
    return self.view.bounds.size.width; 
}
Ing. Ron
  • 2,005
  • 2
  • 17
  • 33
0

I know this question is not tagged for swift, but just in case somebody is looking for the Swift 3.0 version, here it is.

/* Called by the picker view when it needs the view to use for a given row in    
 a given component. If the previously used view (the view parameter) is adequate,    
 return that. If you return a different view, the previously used view is     
released. The picker view centers the returned view in the rectangle for row.    

 */
func pickerView(_ pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusing view: UIView?) -> UIView {

    var label = UILabel(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(300), height: CGFloat(37)))


    let booking = self.bookingInfo[row]  //bookingInfo is an array of elements
      label.text = String(booking.BookingNumber) + String(booking.DateAndTime)
        label.textAlignment = .left
         return label
}
bibscy
  • 2,598
  • 4
  • 34
  • 82
0

Modernized James Boutcher to swift 5. I precompute while the OP does an attribution directly in attributedTitleForRow

    pickerData = pickerData.map {
        let ps = NSMutableParagraphStyle()
        ps.alignment = .center;

        let paraAttributes:[NSAttributedString.Key : Any] = [ NSAttributedString.Key.paragraphStyle: ps]

        let res = NSMutableAttributedString(attributedString: $0)
        res.addAttributes(paraAttributes, range: NSRange(location: 0, length: res.length))
        return res
    }
Anton Tropashko
  • 5,486
  • 5
  • 41
  • 66
0

It took me a long time to realize I'm just missing this single line of code:

pickerView.autoresizingMask = .flexibleWidth

Siklab.ph
  • 991
  • 11
  • 17