使用UIAppearance自定义iOS UIDatepicker

13

1
请原谅这张巨大的图片... - daihovey
您是只需要UIDatePicker中的两个组件,还是只需要将文本的白色字体进行自定义呢? - Kuldeep
尽可能地自定义:字体、颜色,一切都要。 - daihovey
请看一下,我已经定制了选择器的内部视图,您可以根据需求更改代码。 - Kuldeep
你在使用我提供的方法自定义选择器内容时遇到了任何问题吗? - Kuldeep
8个回答

28
API无法提供此功能。您可以使用UIPickerView而不是UIDatePicker来制作一个非常逼真的副本。

由于UIDatePicker或UIPickerView没有UI_APPEARANCE_SELECTOR,即使您不能像其UIControl那样更改UIDatePicker内容的外观,也没有任何委托,因此它具有其本机外观,而在UIPickerView的情况下,您可以更改其内容的外观,类似于UITableView。

#pragma mark -
#pragma mark UIPicker Delegate & DataSource

- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
    return 2;
}

// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
    return 100;
}
//- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:  (NSInteger)component {
     //    return [NSString stringWithFormat:@"%d",row];
//}
- (UIView *)pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view {

      UILabel *label= [[[UILabel alloc] initWithFrame:CGRectMake(30.0, 0.0, 50.0, 50.0)] autorelease];
      [label setBackgroundColor:[UIColor clearColor]];
      [label setTextColor:[UIColor blueColor]];
      [label setFont:[UIFont boldSystemFontOfSize:40.0]];
      [label setText:[NSString stringWithFormat:@"%d",row]];

      return label;
}

在此输入图片描述

看看这个。


4
在你的实现文件中添加此方法。
-(UIView *)pickerViews{

    return ([datePicker.subviews objectAtIndex:0]);
}

-(void)viewDidLoad{

    [super viewDidLoad];

    [[self pickerViews].subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
        NSLog(@"%@ --- > %i",obj, idx);
    }];
}

当你运行你的应用程序时,它会在控制台上显示datePicker的所有子视图,只需选择任何索引并逐个修改它们。
修改viewDidLoad并插入以下代码。
UIView *background = (UIView *)[[self pickerViews].subviews objectAtIndex:0];
background.backgroundColor = [UIColor clearColor];

UIView *wheel2 = (UIView *)[[self pickerViews].subviews objectAtIndex:4];
wheel2.backgroundColor = [UIColor redColor];

UIView *wheel3 = (UIView *)[[self pickerViews].subviews objectAtIndex:11];
wheel3.backgroundColor = [UIColor redColor];

在这种情况下,我更改了索引为"0"、"4"、"11"的背景颜色。

3

iOS 5引入了UIAppearance协议,该协议可让您自定义多个UI元素。UIDatePicker恰好符合此协议,因此这可能是最简单的方法。也就是说,如果您只想支持iOS 5用户。Matthew的选项可能是下一个最好的选择,这也适用于旧版本的iOS。


谢谢,我忘记了 UIAppearance。 - daihovey
抱歉 Scott,我无法使 UIAppearance 在 UIDatePicker 上工作。请查看编辑后的问题。 - daihovey
这应该是一条注释,而不是答案,因为它只建议使用UIAppearance,而没有说明如何在这种情况下使用它。 - Aleksander Azizi
不,您不能使用外观来更改 UIDatePicker 的图形。请查看我的答案以获取更多见解。 - marzapower

3

改变 UIDatePicker 的外观似乎相当困难。

在我看来,你提供的示例是对一个简单的带有两个列和可能模拟无限滚动的 UIPickerView 进行的复杂自定义(就像 Apple 在日期选择器中所做的那样,而且很容易实现)。

你可以通过 UIAppearance 代理改变 UIDatePicker 的一些细节,就像这个示例中所看到的:

UIDatePicker *picker = [UIDatePicker appearance];
picker.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.3];

UIView *view;
view = [UIView appearanceWhenContainedIn:[UITableView class], [UIDatePicker class], nil];
view.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5];

UILabel *label = [UILabel appearanceWhenContainedIn:[UITableView class], [UIDatePicker class], nil];
label.font = [UIFont systemFontOfSize:[UIFont systemFontSize]];
label.textColor = [UIColor blueColor];

使用以下代码片段可以在应用程序开始时更改日期选择器中只有几个主要组件的外观(请尝试一下)。

标签是无法自定义的(此测试代码证明了这一点);显然,它们每次旋转列时都会改变外观,因为它们被放置在自定义的UITableView控制器内部。

要完全更改这些外观,您可能应该使用来自Apple的私有API,这最终会导致您的应用被拒绝

如果您只需要一个自定义的小时-分钟选择器(如您的屏幕截图所示),则可以通过扩展UIPickerView类或将适当的代理分配给UIPickerView实例来完全自定义外观。

通过

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

使用委托的方法,您可以定制选择器视图中的单个元素外观。接着,您需要适当处理数据源,使选择器的两个组件具备虚拟无限的功能。


我已经查看了UIApperance,但仍然不知道如何更改UIDatePicker的文本颜色。它支持吗? - Michael Rowe
正如我在答案中所说,标签是不可能自定义的。 - marzapower

0

更改日期选择器的颜色:

[datePickerView setValue:self.pickerLabelColor forKey:@"textColor"];

而要更改字体,我知道的唯一方法是:

创建类别UIFont+System并将此代码放入其中

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
    + (UIFont *)systemFontOfSize:(CGFloat)fontSize
    {
        return [UIFont fontWithName:fontName size:fontSize];
    }
#pragma clang diagnostic pop

这将在您的应用程序中的其他位置设置字体(通过您的字体替换系统字体)。


0
你可以使用两个UIScrollViews自己实现,一个用于小时,另一个用于分钟。当滚动视图停止移动时,你只需要找出每个滚动视图的contentOffset即可,大致如下所示:
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
  if (!decelerate) {
    // get the offset here
  }
}

- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
  // also get the offset here
}

获取内容偏移值并将其转换为小时值和分钟值,可能是通过将内容偏移的纵向位置分别除以24或60来实现。 您需要自己制作定制艺术品。


1
请注意选择器具有“无限”滚动功能:当您到达末尾(比如59)时,您会回到开头。事实上,真正的末尾和开头并不存在,但由于其中的数字而呈现出这种情况。当自定义UIScrollViews以模仿UIDatePicker行为时,请务必牢记这一点。 - Scott Berrevoets
是的,那是真的。我刚刚下载了优衣库应用程序进行了检查,它也需要伪造无限滚动(这当然还会使数学变得更加复杂),并且还需要使用分页技巧来使滚动视图锁定到特定位置。 - Matthew Gillingham
没有完全考虑清楚,我认为UITableView可能是一个选择。没有涉及复杂数学,只需在滚动时慢慢添加单元格即可。重用单元格只会带来少量性能损失,并且使用“scrollToRowAtIndexPath”将有利于位置锁定机制。 - Scott Berrevoets

-1
你应该查看苹果的UICatalog。它包含了UIDatePicker可以使用的所有方法,包括自定义日期选择器方法。请参考此链接developer.apple.com/library/ios/samplecode/UICatalog/。此外,他们还实现了标准开关和导航栏,这些都在后面给出了。

-1

使用两个UITableViews的组合是最好的方法。

UITableViewUIScrollView的子视图,因此它处理以下事件:

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{

}

在获取位置后,只需使用以下方法将表格滚动到中心

[myTableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionMiddle animated:YES];

希望这能有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接