My question is the following. Actually, I use segment control with images instead of text.
So, for images I write this code:
[self.segmentedControl setDividerImage:[UIImage imageNamed:#"DividerImageLeft.png"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[self.segmentedControl setDividerImage:[UIImage imageNamed:#"DividerImageRight.png"] forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.segmentedControl setImage:[[UIImage imageNamed:#"segment_left.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forSegmentAtIndex:1];
[self.segmentedControl setImage:[[UIImage imageNamed:#"segment_right.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forSegmentAtIndex:0];
As the result, there is a white line between divider and segments (It is only for iOS 7.0+, because it works fine without divider image on iOS 6.1.3 and lower). How can I remove it?
https://www.evernote.com/shard/s305/sh/cda3f2b3-74e6-4268-9d0d-278be9f9e95f/d4110a56f9fe38311cfbe7001d6f9825
Related
I have a segmented control with custom images for segments. I have created it as follows
[repaymetSegmentedControl setBackgroundImage:[UIImage imageNamed:#"-SingleJointOffState"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setBackgroundImage:[UIImage imageNamed:#"-SingleJointOnState"] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"on_div"] forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"off_div"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
CGRect frameSeg= repaymetSegmentedControl.frame;
[repaymetSegmentedControl setFrame:CGRectMake(frameSeg.origin.x, frameSeg.origin.y-5, frameSeg.size.width, frameSeg.size.height + 15)];
Here when I run the app I am selecting one of the segments based on preferences. It appears as shown in image. Not sure what's wrong with it.
The images being used are as follows
Using this code in viewDidLoad gave me the result that I think you are looking for (I renamed your images to make things a bit clearer for me).
[repaymetSegmentedControl setBackgroundImage:[UIImage imageNamed:#"whiteBG"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControll setBackgroundImage:[UIImage imageNamed:#"pinkBG"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setBackgroundImage:[UIImage imageNamed:#"pinkBG"] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor blackColor]} forState:UIControlStateNormal ];
[repaymetSegmentedControll setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]} forState:UIControlStateHighlighted ];
[repaymetSegmentedControl setTitleTextAttributes:#{NSForegroundColorAttributeName:[UIColor whiteColor]} forState:UIControlStateSelected ];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"pinkDivider"] forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"pinkDivider"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"pinkDivider"] forLeftSegmentState:UIControlStateHighlighted rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"pinkDivider"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"whiteDivider"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
Using this code, the result is like this . Attached Image:
My guess is that the text color for selected segments is set to black and white for the other. So in your screenshot the middle segment is selected.
The problem could be somewhere else:
[repaymetSegmentedControl setBackgroundImage:[UIImage imageNamed:#"-SingleJointOffState"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setBackgroundImage:[UIImage imageNamed:#"-SingleJointOnState"] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
It seems weird to have image names starting with -.
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"on_div"] forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[repaymetSegmentedControl setDividerImage:[UIImage imageNamed:#"off_div"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
You seem to be missing right selected/left normal option.
Also as your design seems pretty flat, I'm not sure you need any of those.
Finally could you attach all the images to the question?
Your segment divider image should be the same height as the background images.
I have an application in which I wanted to customize the segment control using buttons like in Instagram. I had done like this
[[UISegmentedControl appearanceWhenContainedIn:[UISearchBar class], nil] setSegmentedControlStyle:UISegmentedControlStyleBar];
[[UISegmentedControl appearanceWhenContainedIn:[UISearchBar class], nil] setTintColor:[UIColor clearColor]];
[[UISegmentedControl appearance] setBackgroundImage:[UIImage imageNamed:#"back_bg.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setBackgroundImage:[UIImage imageNamed:#"white_btn.png"]
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:[UIImage imageNamed:#"segcontrol_uns-sel.png"]
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:[UIImage imageNamed:#"segcontrol_sel-uns.png"]
forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
But when I am selecting the button it is highlighting except the division image. So its looking wired. Can anybody help me on this?
Try with this:
UIImage *defaultBgImage,*selectedBgImage,*segcontrol_uns,*segcontrol_sel;
if ([UIImage instancesRespondToSelector:#selector(imageWithRenderingMode:)])
{
defaultBgImage = [[UIImage imageNamed:#"back_bg.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
selectedBgImage = [[UIImage imageNamed:#"white_btn.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
segcontrol_uns = [[UIImage imageNamed:#"segcontrol_uns-sel.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
segcontrol_sel = [[UIImage imageNamed:#"segcontrol_sel-uns.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}
else
{
defaultBgImage = [UIImage imageNamed:#"back_bg.png"];
selectedBgImage = [UIImage imageNamed:#"white_btn.png"];
segcontrol_uns = [UIImage imageNamed:#"segcontrol_uns-sel.png"];
segcontrol_sel = [UIImage imageNamed:#"segcontrol_sel-uns.png"];
}
[[UISegmentedControl appearance] setBackgroundImage:defaultBgImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setBackgroundImage:selectedBgImage
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segcontrol_uns forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segcontrol_sel forLeftSegmentState: UIControlStateSelected rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
You need to do "setBackgroundImage" for four different states.
UIControlStateNormal
UIControlStateSelected
UIControlStateHighlighted
UIControlStateSelected | UIControlStateHighlighted (When pressing already selected segment)
And do "setDividerImage" for seven different states.
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal
forLeftSegmentState:UIControlStateHighlighted rightSegmentState:UIControlStateSelected
forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateHighlighted
forLeftSegmentState:UIControlStateSelected | UIControlStateHighlighted rightSegmentState:UIControlStateNormal
forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected | UIControlStateHighlighted
forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal
You need the following images for three segments
1. segment bg selected
2. segment bg unselected
3. segment middle, left selected, right unselected
4. segment middle, left unselected, right selected
5. segment middle, both left & right selected
6. segment middle, both left & right unselected
I had written this code for a 3 Segment control. However you can tweak it as per your needs.
/* 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];
Following code fixed it for me:
[[UISegmentedControl appearanceWhenContainedIn:[InboxViewController class], nil] setBackgroundImage:[UIImage imageNamed:#"btn-gray"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearanceWhenContainedIn:[InboxViewController class], nil] setBackgroundImage:[UIImage imageNamed:#"btn-gray"] forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearanceWhenContainedIn:[InboxViewController class], nil] setBackgroundImage:[UIImage imageNamed:#"btn-gray"] forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearanceWhenContainedIn:[InboxViewController class], nil] setBackgroundImage:[UIImage imageNamed:#"btn-gray"] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
So after I customize the UISegmentedControl, everything got messed up, the label got shifted and there is a white vertical line which I don't know where it came from. The divider also got off-center, I have checked that the black line is at 40-41px of a 80px image, so it must be centered. Want am I doing wrong or have anybody experience this before?
Before Customization:
After Customization:
note: the divider images is a horizontal flip of each other.
Code:
UIImage *un_sel = [UIImage imageNamed:#"divider-un-sel"];
UIImage *sel_un = [UIImage imageNamed:#"divider-sel-un"];
[_segmentControl setDividerImage:un_sel forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[_segmentControl setDividerImage:sel_un forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
UIImage *normal = [[UIImage imageNamed:#"segment-normal"] stretchableImageWithLeftCapWidth:20 topCapHeight:0];
UIImage *selected = [[UIImage imageNamed:#"segment-selected"] stretchableImageWithLeftCapWidth:20 topCapHeight:0];
[_segmentControl setBackgroundImage:normal forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[_segmentControl setBackgroundImage:selected forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
Solved the problem by using
[[UIImage imageNamed:#"segment-normal"] resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
instead of stretchableImageWithLeftCapWith:topCapHeight
I'm working on an iOS project and came across this strange issue. I have a UISegmentedControl element of bar style. It has 3 segments. The segments have fixed sizes of 80. I also have 3 images with each segment selected to set as background. Here is one of them`
When view is loaded, one of the segments is set as selected and this image is set as background like this:
[self.genderSelectionButton setBackgroundImage:[UIImage imageNamed:#"gender-switch01.png"] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
Now when I run the project on 5.1 Simulator, I get this distorted view for segmented button:
As you can see, the middle segment keeps the size I gave, but the image is kind of stretched from the middle to the edges.
Also selected segment is highlighted even though I have set it to NO.
In the method that listens to button selection, I change background image and get the following:
(background image is stretched again...)
Almost the same happens on iOS6.
Now am I doing something wrong, or is there a way to fix this??
EDIT
Found a better implementation with separate images for normal button, selected button and dividers. See the answer below.
It appears that setting full background image is not the best way to handle custom segmented button. Example found here.
Here is the basic code that does everything:
UIImage *segmentSelected =
[[UIImage imageNamed:#"segcontrol_sel.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
UIImage *segmentUnselected =
[[UIImage imageNamed:#"segcontrol_uns.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 0, 15)];
UIImage *segmentSelectedUnselected =
[UIImage imageNamed:#"segcontrol_sel-uns.png"];
UIImage *segUnselectedSelected =
[UIImage imageNamed:#"segcontrol_uns-sel.png"];
UIImage *segmentUnselectedUnselected =
[UIImage imageNamed:#"segcontrol_uns-uns.png"];
[[UISegmentedControl appearance] setBackgroundImage:segmentUnselected
forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setBackgroundImage:segmentSelected
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedUnselected
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentSelectedUnselected
forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance]
setDividerImage:segUnselectedSelected
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
I have a view with 2 uisegmentedcontrols, one along the bottom and one in the nav bar. The bottom one is working fine, the one in the nav bar appears, but does not pick up any touch events. Code for the bottom segment (working) is:
footerSegment = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"1", #"2", nil]];
[footerSegment setFrame:CGRectMake(5, 6, 310, 30)];
[footerSegment setSegmentedControlStyle:UISegmentedControlStyleBar];
footerSegment.selectedSegmentIndex = 0;
//segmentFiltering.tintColor = [UIColor colorWithWhite:80.0/255.0 alpha:1.0];
[footerSegment addTarget:self action:#selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
[footerSegment setTag:0];
[footerSegment setBackgroundColor:[UIColor clearColor]];
UIImage *segSelected = [[UIImage imageNamed:#"segment_sel.png"] stretchableImageWithLeftCapWidth:5.0 topCapHeight:0];
UIImage* menuRightImage = [[UIImage imageNamed:#"button.png"] stretchableImageWithLeftCapWidth:5.0 topCapHeight:0.0];
[footerSegment setBackgroundImage:menuRightImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[footerSegment setBackgroundImage:segSelected
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
UIImage *segmentDividerImg = [[UIImage imageNamed:#"div.png"] stretchableImageWithLeftCapWidth:0 topCapHeight:0];
// Image between two unselected segments.
[footerSegment setDividerImage:segmentDividerImg forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
// Image between segment selected on the left and unselected on the right.
[footerSegment setDividerImage:segmentDividerImg forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
// Image between segment selected on the right and unselected on the right.
[footerSegment setDividerImage:segmentDividerImg forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[footerToolBar addSubview:footerSegment];
Code for the navbar one is below (visable but doesn't work):
headSegment = [[UISegmentedControl alloc]
initWithItems:[NSArray arrayWithObjects:#"A", #"B", nil]];
[headSegment setFrame:CGRectMake(50, 7, 200, 29)];
[headSegment setSegmentedControlStyle:UISegmentedControlStyleBar];
headSegment.selectedSegmentIndex = 0;
[headSegment addTarget:self action:#selector(segmentAction:) forControlEvents:UIControlEventValueChanged];
[headSegment setBackgroundColor:[UIColor clearColor]];
[headSegment setBackgroundImage:menuRightImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[headSegment setBackgroundImage:segSelected forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[headSegment setDividerImage:segmentDividerImg forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[headSegment setDividerImage:segmentDividerImg forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[headSegment setDividerImage:segmentDividerImg forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[headSegment setTag:1];
[self.navigationController.navigationBar addSubview:headSegment];
Code for the action:
-(void)segmentAction:(UISegmentedControl*)sender
{
if(sender.tag == 0){
NSLog(#"Selected index: %d", sender.selectedSegmentIndex);
}
else{
if (sender.selectedSegmentIndex = 1) {
NSLog(#"Selected HEAD index: %d", sender.selectedSegmentIndex);
}
}
[self.navigationController.navigationBar addSubview:headSegment];
That is not how you add things to a navigation bar. You must work by way of your navigation controller's navigationItem. You can make the segmented control its titleView or you can wrap it in a bar button item and make that one of the right or left buttons.