自定义左右UISegmentedControl按钮

26

我想自定义以下分段控件,使用左侧图片代替第一个按钮,并使用右侧图片代替第二个按钮。如何使用UIAppearance实现?

我想改变以下分段控件:

进入图像描述

类似下面的样式:

进入图像描述

我想使用自定义图片是因为我想更改按钮的角落。如果您看蓝色分段控件,它的角落更加方正(我的图片有自己的角落)。

我想实现这样的效果,但没有成功:

UIImage *leftImage = [[UIImage imageNamed:@"leftControl.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
UIImage *rightImage = [[UIImage imageNamed:@"rightControl.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];

[[UISegmentedControl appearance] setBackgroundImage:leftImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault ];
[[UISegmentedControl appearance] setBackgroundImage:rightImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];

我在这里打包了一些图片(包括Photoshop文件)和代码:https://dev59.com/gWkv5IYBdhLWcg3wfA0P#16819218 - iwasrobbed
3个回答

112
您需要提供以下图像:
  • 选择的分段背景(包含左右两端)
    enter image description here
  • 未选择的分段背景(包含左右两端)
    enter image description here
  • 中间分段,左侧选择、右侧未选择
    enter image description here
  • 中间分段,左侧未选择、右侧选择
    enter image description here
  • 中间分段,左右两侧都选择
    enter image description here
  • 中间分段,左右两侧都未选择
    enter image description here

然后使用以下代码进行设置:

/* Unselected background */
UIImage *unselectedBackgroundImage = [[UIImage imageNamed:@"segment_background_unselected"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];
[[UISegmentedControl appearance] setBackgroundImage:unselectedBackgroundImage
                                           forState:UIControlStateNormal
                                         barMetrics:UIBarMetricsDefault];

/* Selected background */
UIImage *selectedBackgroundImage = [[UIImage imageNamed:@"segment_background_selected"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)];
[[UISegmentedControl appearance] setBackgroundImage:selectedBackgroundImage
                                           forState:UIControlStateSelected
                                         barMetrics:UIBarMetricsDefault];

/* Image between two unselected segments */
UIImage *bothUnselectedImage = [[UIImage imageNamed:@"segment_middle_unselected"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 0, 15, 0)];
[[UISegmentedControl appearance] setDividerImage:bothUnselectedImage
                             forLeftSegmentState:UIControlStateNormal
                               rightSegmentState:UIControlStateNormal
                                      barMetrics:UIBarMetricsDefault];

/* Image between segment selected on the left and unselected on the right */
UIImage *leftSelectedImage = [[UIImage imageNamed:@"segment_middle_left_selected"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 0, 15, 0)];
[[UISegmentedControl appearance] setDividerImage:leftSelectedImage
                             forLeftSegmentState:UIControlStateSelected
                               rightSegmentState:UIControlStateNormal
                                      barMetrics:UIBarMetricsDefault];

/* Image between segment selected on the right and unselected on the left */
UIImage *rightSelectedImage = [[UIImage imageNamed:@"segment_middle_right_selected"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 0, 15, 0)];
[[UISegmentedControl appearance] setDividerImage:rightSelectedImage
                             forLeftSegmentState:UIControlStateNormal
                               rightSegmentState:UIControlStateSelected
                                      barMetrics:UIBarMetricsDefault];
请注意,你需要调整可伸缩图片中的帽子尺寸以匹配你的图片。

1
是的,谢谢,这些图片节省了很多时间和研究,非常感谢。 - Tom DeMille
考虑到上述所描述的图像,您是否需要提供高清等效版本(即@2x.png),或者resizableImageWithCapInsets:方法基本上已经为我们处理了这个问题? - avelis
1
@avelis 是的,您必须提供1x和2x图像。 - Maurizio
1
@avelis 像往常一样,您指定标准的 image.png 图像名称,然后操作系统会在必要时将其替换为 image@2x.png - iwasrobbed
非常好!有几个问题。看起来你忘记设置当两个片段都被选中时的中间部分了。此外,如果您想要自定义字体/颜色/阴影等,也可以设置标题属性[[UISegmentedControl appearance] setTitleTextAttributes:...]。 - Craig B
嗨@iWasRobbed,我想要在按下和未按下状态下使用不同的图像,并且每个部分的图像也将不同。我们可以通过使用上面的代码来实现这一点吗? - Ranjit

4
Maurizio的回答对我在工具栏内使用的分段控件并没有奏效,因为分割线图片不够宽,导致控件上出现了幻影线。
所以我自己制作了一份。以下是在Xcode中需要的所有图片,并且还提供了Photoshop文件,可用于创建分段控件的图片,以便您更改样式:
https://s3.amazonaws.com/iwasrobbed/stackoverflow/Custom+Segmented+Control.zip
将此代码放入AppDelegate中,即可使用附带的图片更改工具栏中所有分段控件的外观。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [self customizeAppAppearance];
}

- (void)customizeAppAppearance
{
    // Toolbar
    [[UIToolbar appearance] setBackgroundImage:[[UIImage imageNamed:@"toolbar.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(22, 5, 22, 5)] forToolbarPosition:UIToolbarPositionAny barMetrics:UIBarMetricsDefault];

    // Segmented Controls within Toolbars

    // Unselected background
    UIImage *unselectedBackgroundImage = [[UIImage imageNamed:@"segmentInactive.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 15, 15, 15)];
    [[UISegmentedControl appearanceWhenContainedIn:[UIToolbar class], nil] setBackgroundImage:unselectedBackgroundImage
                                                                                     forState:UIControlStateNormal
                                                                                   barMetrics:UIBarMetricsDefault];

    // Selected background
    UIImage *selectedBackgroundImage = [[UIImage imageNamed:@"segmentActive.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 15, 15, 15)];
    [[UISegmentedControl appearanceWhenContainedIn:[UIToolbar class], nil] setBackgroundImage:selectedBackgroundImage
                                                                                     forState:UIControlStateSelected
                                                                                   barMetrics:UIBarMetricsDefault];

    // Image between two unselected segments
    UIImage *bothUnselectedImage = [[UIImage imageNamed:@"segmentBothInactive.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 10, 15, 10)];
    [[UISegmentedControl appearanceWhenContainedIn:[UIToolbar class], nil] setDividerImage:bothUnselectedImage
                                                                       forLeftSegmentState:UIControlStateNormal
                                                                         rightSegmentState:UIControlStateNormal
                                                                                barMetrics:UIBarMetricsDefault];

    // Image between segment selected on the left and unselected on the right
    UIImage *leftSelectedImage = [[UIImage imageNamed:@"segmentLeftActiveRightInactive.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 0, 15, 0)];
    [[UISegmentedControl appearanceWhenContainedIn:[UIToolbar class], nil] setDividerImage:leftSelectedImage
                                                                       forLeftSegmentState:UIControlStateSelected
                                                                         rightSegmentState:UIControlStateNormal
                                                                                barMetrics:UIBarMetricsDefault];

    // Image between segment selected on the right and unselected on the left
    UIImage *rightSelectedImage = [[UIImage imageNamed:@"segmentRightActiveLeftInactive.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(15, 0, 15, 0)];
    [[UISegmentedControl appearanceWhenContainedIn:[UIToolbar class], nil] setDividerImage:rightSelectedImage
                                                                       forLeftSegmentState:UIControlStateNormal
                                                                         rightSegmentState:UIControlStateSelected
                                                                                barMetrics:UIBarMetricsDefault];
}

2
你需要制作一张所有部分都可以使用的背景图片,还需要一张仅为按钮左边缘的图片、一张连接两个按钮的图片以及一张右边缘的图片。其中有些需要为多种状态制作。以下是你需要制作的图片列表:
  • 左侧帽子,已选
  • 左侧帽子,未选
  • 段落背景,已选
  • 段落背景,未选
  • 右侧帽子,已选
  • 右侧帽子,未选
  • 中间帽子,左侧已选右侧未选
  • 中间帽子,左侧未选右侧已选
  • 中间帽子,两侧都选
  • 中间帽子,两侧都未选
对于中间的帽子,你可以像这样放置它们:(来自苹果文档的文字)。
// Image between two unselected segments.
[mySegmentedControl setDividerImage:image1 forLeftSegmentState:UIControlStateNormal
              rightSegmentState:UIControlStateNormal barMetrics:barMetrics];
// Image between segment selected on the left and unselected on the right.
[mySegmentedControl setDividerImage:image1 forLeftSegmentState:UIControlStateSelected
              rightSegmentState:UIControlStateNormal barMetrics:barMetrics];
// Image between segment selected on the right and unselected on the right.
[mySegmentedControl setDividerImage:image1 forLeftSegmentState:UIControlStateNormal
              rightSegmentState:UIControlStateSelected barMetrics:barMetrics];

如果您正在使用UIAppearance,显然您需要将这些消息发送到外观代理。

以上图像列表与设置控件/外观代理的背景/分隔符图像的调用之间的确切映射是什么? - Thom

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