原文链接:http://www.raywenderlich.com/4344/user-interface-customization-in-ios-5

在ios5推出之前,要实现标准界面的定制设计,对于开发者来说可没有那么简单。尽管开发者可以通过重写drawRect是一个不错的办法,但开发者也很头痛。

现在有了ios5了,UIKit添加了许多控件元素的外观。

image

 

开始前的准备 
首先请下载这个初始项目(http://www.raywenderlich.com/downloads/SurfsUpStarter.zip) 
我已经创建好了一个简单的应用,这样大家就可以把重点放在学习如何定制UIKit界面元素上。 
当你打开项目之后,先看看其中的代码和XIB文件。你会发现主视图呈现了一个冲浪之旅的列表,而细节视图则匀速我们获取每个冲浪之旅的详细信息。 
看完基本代码和XIB文件后,让我们编译运行项目,会看到以下的两个视图。

image

现在我们要做的事情是,把这个完全标准的界面改造成具有独风格的定制界面。

添加背景图片 
事实上,我们已经把所需要的资源图片都放在Resources里面了,所以要做的只是添加代码而已。 
  
在images文件夹中有一个bg_sand.png图片。我们打算用它当做细节视图的背景图片。 
  
打开DetailViewController.m,创建一个viewDidLoad方法如下: 
  
  
-(void)viewDidLoad{ 
  
  [superviewDidLoad]; 
  [[selfview]setBackgroundColor:[UIColorcolorWithPatternImage:[UIImageimageNamed:@"bg_sand"]]]; 
  

  
无疑,这是设置背景图片的最佳方式,虽然没有backgroundImage这样的属性,但是使用backgroundColor属性我们同样可以实现这个目的! 
  
编译运行项目,可以看到以下界面: 
  
 image 
定制UINavigationBar 
  
在images文件夹中,我们将使用以下两个图片来定制导航栏:surf_gradient_textured_32.png和surf_gradident_textured_44.png。 
  
我们希望在导航栏中从左到右重复铺设这些图片。之所有用了两个不同的高度,是因为当导航栏切换到横屏模式时会缩小。 
  
要实现以上效果,iOS提供了两个新的API: 
1.UINavigationbar现在可以设置backgroundImage属性 
2.UIImage提供了新的resizableImageWithCapInsets方法,方便创建可调整大小的图片。 
  
当然,我们可以进入细节视图,并使用以上API来直接设置导航栏的背景图片。但如果这样做,那就得在列表视图或应用的其它视图中手动修改。 
  
幸运的是,iOS5允许我们一次性定制用户界面元素,从而让“处于同一级别的”界面元素使用类似的定制。 
  
在SurfsUpAppDelegate.m文件中,在application:didFinishLaunchingWithOptions:方法的上面添加一个新的方法如下: 
  
-(void)customizeAppearance{ 
  
//create resizable images创建可调整大小的图像 
UIImage *gradientImage44 = [[UIImageimageNamed:@"surf_gradient_textured_44"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)]; 
UIImage *gradientImage32 = [[UIImageimageNamed:@"surf_gradient_textured_32"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)]; 
  
//set the background image for *all* UINavigationBars为所有导航栏设置背景图片 
  [[UINavigationBarappearance]setBackgroundImage:gradientImage44forBarMetrics:UIBarMetricsDefault]; 
  [[UINavigationBarappearance]setBackgroundImage:gradientImage32forBarMetrics:UIBarMetricsLandscapePhone]; 
  
//customize the title text for *all* UINavigationBars为所有导航栏设置标题文本 
  [[UINavigationBarappearance]setTitleTextAttributes: 
   [NSDictionarydictionaryWithObjectsAndKeys: 
    [UIColorcolorWithRed:255.0/255.0green:255.0/255.0blue:255.0/255.0alpha:1.0], 
UITextAttributeTextColor, 
    [UIColorcolorWithRed:0.0green:0.0blue:0.0alpha:0.8], 
UITextAttributeTextShadowColor, 
    [NSValuevalueWithUIOffset:UIOffsetMake(0, -1)], 
UITextAttributeTextShadowOffset, 
    [UIFontfontWithName:@"Arial-Bold"size:0.0], 
UITextAttributeFont, 
nil]]; 
  

  
在以上的代码中,头两行的作用是使用resizableImageWithCapInsets方法创建了可伸缩的图像。需要注意的是,该方法取代了之前版本中使用的stretchableImageWithLeftCapWidth:topCapHeight:方法(已被删除)。 
  
关于cap insets,我们只需简单的设置指定图像在顶部,左端,右端和下部的固定区域。在这里,我们希望整个图片都伸缩,所以为每个端都设置了0。 
  
接下来的两行代码使用appearance(外观)代理将可伸缩图片设置为背景图片,并指定了导航栏的测量方式。 
  
最后几行代码指定了细节视图中的标题样式。我们传入了标题文本属性词典,相关的可用键值包括: 
UITextAttributeFont 
UITextAttributeTextColor 
UITextAttributeTextShadowColor 
UITextAttributeTextShadowOffset 
  
Ok,差不多搞定了,只需要在application:didFinishLaunchingWithOptions:方法的顶部添加一行代码: 
[selfcustomizeAppearance]; 
  
编译运行应用,并切换设备的朝向,可以看到以下画面:

 image 
  
  
定制UIBarButtonItem 
  
  
打开images,找到button_textured_24.png和button_textured_30.png两个文件,我们将用它们来设置导航栏中的按钮外观。 
  
注意我们需要将按钮图像设置为可调整大小的,因为按钮的宽度取决于其中的文本。 
对于这些按钮,我们不需要最左和最右的5个像素也伸缩,所以需要将left和right cap insets设置为5。 
  
在customizeAppearance方法的最后添加以下代码: 
  
//customize the apperance for UIBarButtonItems 
  
UIImage *button30 = [[UIImageimageNamed:@"button_textured_30"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)]; 
UIImage *button24 = [[UIImageimageNamed:@"button_textured_24"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 5)]; 
  
  [[UIBarButtonItemappearance] setBackgroundImage:button30forState:UIControlStateNormalbarMetrics:UIBarMetricsDefault]; 
  [[UIBarButtonItemappearance] setBackgroundImage:button24forState:UIControlStateNormalbarMetrics:UIBarMetricsLandscapePhone]; 
  
  
  [[UIBarButtonItemappearance]setTitleTextAttributes: 
   [NSDictionarydictionaryWithObjectsAndKeys: 
    [UIColorcolorWithRed:220.0/255.0green:104.0/255.0blue:1.0/255.0alpha:1.0], 
UITextAttributeTextColor, 
    [UIColorcolorWithRed:1.0green:1.0blue:1.0alpha:1.0], 
UITextAttributeTextShadowColor, 
    [NSValuevalueWithUIOffset:UIOffsetMake(0, 1)], 
UITextAttributeTextShadowOffset, 
    [UIFontfontWithName:@"AmericanTypewriter"size:0.0], 
UITextAttributeFont, 
nil] 
forState:UIControlStateNormal]; 
  
以上代码其实和定制导航栏的差不多。首先我们还是为按钮创建了可伸缩的图像,并设置为背景图片。然后我们指定了文本的格式。 
  
其中的”back”按钮需要特殊定制,因为它需要看起来与众不同。 
让我们在customizeApperance方法的最后添加以下代码来特殊对待back按钮: 
  
//customize the appeance for "back" on UIBarButtonItems 
  
UIImage *buttonBack30 = [[UIImageimageNamed:@"button_back_textured_30"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 13, 0, 5)]; 
UIImage *buttonBack24 = [[UIImageimageNamed:@"button_back_textured_24"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 12, 0, 5)]; 
  
  [[UIBarButtonItemappearance]setBackButtonBackgroundImage:buttonBack30forState:UIControlStateNormalbarMetrics:UIBarMetricsDefault];
  [[UIBarButtonItemappearance]setBackButtonBackgroundImage:buttonBack24forState:UIControlStateNormalbarMetrics:UIBarMetricsLandscapePhone];
  
  
需要注意的是,我们为back按钮设置了不同的cap inset值。同时,UIBarButtonItem还有一个专门的backButtonBackgroundImage属性可以使用。 
  
编译运行,可以看到下图: 
 

 image 
  
定制UITabBar 
  
在iOS5中提供了一个API来设置UITabBar的背景图片,以及表示选中的图片。 
  
在customizeAppearance方法的底部添加以下代码: 
  
//customize the apperance for UITabBar 
  
UIImage *tabBackground = [[UIImageimageNamed:@"tab_bg"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 0, 0, 0)]; 
  [[UITabBarappearance]setBackgroundImage:tabBackground]; 
  [[UITabBarappearance]setSelectionIndicatorImage:[UIImageimageNamed:@"tab_select_indicator"]]; 
  
  
我想这三行代码基本不需要再解释了。 
  
编译运行项目,会看到以下界面: 
  
 image

  
  
定制UISlider 
  
  
在iOS5中,我们只需设置maximusTrackImage,minimumTrackImage和thumbImage属性即可轻松定制滑动控制。 
  
让我们在customizeAppearance方法的底部添加以下代码: 
  
//customize the apperance for UISlider 
  
UIImage *minImage = [[UIImageimageNamed:@"slider_minimum"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)]; 
UIImage *maxImage = [[UIImageimageNamed:@"slider_maximum"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 5, 0, 0)]; 
UIImage *thumbImage = [UIImageimageNamed:@"thumb"]; 
  
  [[UISliderappearance]setMaximumTrackImage:maxImageforState:UIControlStateNormal]; 
  [[UISliderappearance]setMinimumTrackImage:minImageforState:UIControlStateNormal]; 
  [[UISliderappearance]setThumbImage:thumbImageforState:UIControlStateNormal]; 
  
编译运行,就可以看到定制后的UISlider滑动条! 
  
 

 image 
  
定制UISegmentedControl 
  
  
接下来让我们来定制分段控制。这个元素稍微复杂一点。因为我们需要使用选中和非选中的背景,以及邻近区域的不同状态(如左边选中,右边未选中;左边未选中和右边选中,以及两边都没有选中)。 
  
在customizeAppearance方法的底部添加以下代码: 
  
  
//customize the appearance for UISegmentedControl 
  
UIImage *segmentSelected =[[UIImageimageNamed:@"segcontrol_sel"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)]; 
UIImage *segmentUnselected =[[UIImageimageNamed:@"segcontrol_uns"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)]; 
UIImage *segmentSelectedUnselected =[UIImageimageNamed:@"segcontrol_sel-uns"]; 
UIImage *segUnselectedSelected = [UIImageimageNamed:@"segcontrol_uns-sel"]; 
UIImage *segmentUnselectedUnselected =[UIImageimageNamed:@"segcontrol_uns-uns"]; 
  
  
  [[UISegmentedControlappearance]setBackgroundImage:segmentUnselectedforState:UIControlStateNormalbarMetrics:UIBarMetricsDefault];
  [[UISegmentedControlappearance]setBackgroundImage:segmentSelectedforState:UIControlStateSelectedbarMetrics:UIBarMetricsDefault];
  
  
  [[UISegmentedControlappearance]setDividerImage:segmentUnselectedUnselectedforLeftSegmentState:UIControlStateNormalrightSegmentState:UIControlStateNormalbarMetrics:UIBarMetricsDefault];
  
  [[UISegmentedControlappearance]setDividerImage:segmentSelectedUnselectedforLeftSegmentState:UIControlStateSelectedrightSegmentState:UIControlStateNormalbarMetrics:UIBarMetricsDefault];
  [[UISegmentedControlappearance]setDividerImage:segUnselectedSelectedforLeftSegmentState:UIControlStateNormalrightSegmentState:UIControlStateSelectedbarMetrics:UIBarMetricsDefault];
  
  
编译运行项目,可以看到UISegmentedControl现在是旧貌换新颜了! 
 

image 
  
  
定制UISwitch 
  
截止目前为止,我们还没有找到定制UISwitch的合适方法,但要修改它的tintColor属性还是轻而易举的。 
  
注意到在DetailViewController中,已经有一个IBOutlet- rentSwitch的联系将切换开关和DetailView.xib联系起来。 
  
我们只需在DetailViewController的viewDidLoad方法中添加以下代码即可: 
  
-(void)viewDidLoad{ 
  
  [superviewDidLoad]; 
  [[selfview]setBackgroundColor:[UIColorcolorWithPatternImage:[UIImageimageNamed:@"bg_sand"]]]; 
  [rentSwitchsetOnTintColor:[UIColorcolorWithRed:0green:175.0/255.0blue:176.0/255.0alpha:1.0]]; 

  
编译运行项目,会看到切换开关有了新的颜色! 
 

image 
  
  
定制UILabel 
  
标签是细节视图中的重要组成部分,但我们不会通过appearance代理来进行定制。 
  
打开DetailView.xib,在主视图中选中第一个标签(比如name),然后在右侧面板选择Attributes Inspector,并进行以下设置: 
  
                          Font: Custom 
                          Family: American Typewriter 
                          Style: Regular 
                  Size: 16 
  
同时再修改剩下的两个标签属性:“Experience Level”和”Rent a board” 
  
编译运行项目,会看到标签的外观更养眼一些了。 
  
 

 image 
  
定制UITextField 
  
  
现在,我们的UITextField(文本输入框)已经被设置为使用UITextBorderStyleLine.让我们在Interface Builder中将字体设置为American Typewriter,Size 12,Regular。 
切换到Identity Inspector,你会看到现在的类型是CustomTextField。 
  
现在又该用到drawRect:方法了。为了提供青色的背景,我们需要覆盖drawRect方法。 
  
现在在Xcode中找到我们为此所创建的CustomTextField.m文件,使用以下代码替换drawRect:方法: 
  
  
- (void)drawRect:(CGRect)rect 

//    [superdrawRect:rect]; 
UIImage *textFieldBackground = [[UIImageimageNamed:@"text_field_teal"]resizableImageWithCapInsets:UIEdgeInsetsMake(15, 5, 15, 5)]; 
  
  [textFieldBackgrounddrawInRect:[selfbounds]]; 

  
  
这里我们创建了另一个可伸缩的图像,并在视图边界定义的矩形中绘制。现在可以编译运行项目了。 
 

image

项目源代码:http://easymorse-iphone.googlecode.com/svn/trunk/surf-starter/