views:

2222

answers:

4

I have a custom UIPickerView where I use:

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

to populate the picker with UILabels. Is there a way to disable the behavior of highlighting the selected row when touched?

I think this is a property of the underlying UITableViewCell inherent in the UIPickerView and I can't find a way to change it.

A: 

I guess you may want to look at "showsSelectionIndicator" property of UIPickerView

The showsSelectionIndicator is responsible for displaying the blue bar over the value that will be returned by the picker. It unfortunately has nothing to do with the underlying UITableViewCell structure.
Jon
A: 

I'm not sure if there is an easy way to remove the selection feedback, but you can cover it up if you make the background of the label white and size it to the same dimensions as the blue selection rectangle:

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

    UILabel *pickerRowLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 0.0, 316, 40)];
    pickerRowLabel.backgroundColor = [UIColor whiteColor];
    pickerRowLabel.text = [pickerDataArray objectAtIndex:row]; 
    [self.view addSubview:pickerRowLabel];

    return pickerRowLabel;

}

With a width of 316 the label covers all but a sliver of blue on each side, and at 320 it completely covers the selection feedback but it also starts to cover a bit of the outer wheel gradients, which may or may not bother you.

Halle
+3  A: 

You need to make sure your custom view has the following properties:

  1. It needs to be sized to the same dimensions that the UIPickerView expects based on your delegate methods -- pickerView:rowHeightForComponent: and pickerView:widthForComponent:. The default height is 44 if you're not specifying a custom height.
  2. The background color must be [UIColor clearColor].
  3. The view must capture all touches.

The one gotcha when using UILabel instances as the custom view is that UILabel defaults userInteractionEnabled to NO (UIView, on the other hand, defaults this property to YES).

Based on these requirements, the example code from Halle can be rewritten as follows. This example also correctly reuses previously created views, which is needed for fast scrolling performance.

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

  UILabel *pickerRowLabel = (UILabel *)view;
  if (pickerRowLabel == nil) {
    // Rule 1: width and height match what the picker view expects.
    //         Change as needed.
    CGRect frame = CGRectMake(0.0, 0.0, 320, 44);
    pickerRowLabel = [[[UILabel alloc] initWithFrame:frame] autorelease];
    // Rule 2: background color is clear. The view is positioned over
    //         the UIPickerView chrome.
    pickerRowLabel.backgroundColor = [UIColor clearColor];
    // Rule 3: view must capture all touches otherwise the cell will highlight,
    //         because the picker view uses a UITableView in its implementation.
    pickerRowLabel.userInteractionEnabled = YES;
  }
  pickerRowLabel.text = [pickerDataArray objectAtIndex:row];  

  return pickerRowLabel;
}
Doug Barth
+4  A: 

Setting the userInteractionEnabled property of UILabel to YES fixes the highlighting issue, but it also disables the UIPickerView from autoscrolling to select the row that has been touched.

If you want to disable the highlighting behavior, but maintain the UIPickerView's default autoscrolling functionality, call the setShowSelection function in the UITableCell instances contained in the UIPickerView. A way of doing this is to subclass the UILabel class similar to the following:

PickerViewLabel.h -

#import <UIKit/UIKit.h>

@interface PickerViewLabel:UILabel 
{
}

@end

PickerViewLabel.m -

#import "PickerViewLabel.h"

@implementation PickerViewLabel

- (void)didMoveToSuperview
{
 if ([[self superview] respondsToSelector:@selector(setShowSelection:)])
 {
  [[self superview] performSelector:@selector(setShowSelection:) withObject:NO];
 }
}

@end

Then, where you had previously been returning an instance of UILabel in pickerView:viewForRow:forComponent:reusingView:, return an instance of PickerViewLabel. As an example, using the code from Doug, you would replace all the cases of 'UILabel' with 'PickerViewLabel'. Just remember to remove the pickerRowLabel.userInteractionEnabled = YES; line.

Christine
Hi Christine, I implemented the same above code but still blue selection comes at both end of selected row. When I try to debug the code, I found that didMoveToSuperview is not called anywhere. Can you help me? Thanks.
cooliPhoneGuy
Hey Shailesh, It's hard to say w/o seeing your code, but I have a few ideas as to why it would not be called. 'didMoveToSuperview' is a function of UIView that gets called automatically anytime that a UIView is added or removed from a view. Is your custom view definitely being added to the screen? If you do a quick test and add an instance of your class as a subview of a UIViewController's view, do you see 'didMoveToSuperview' being called then? If not, I would guess that you have a typo somewhere in the function declaration.
Christine