I have a UISegmentedControl with a customized appearance, and I believe I have all of the necessary assets to have the correct appearance, and in most cases the appearance is as desired, however when I tap on one of the segments, before releasing, the edges of the segment, right about where the divider image is supposed to be, the appearance suddenly becomes incorrect. Attached are some screenshots, and here is my code for setting the different images:
UIImage *segmentUnselectedBG = [[UIImage imageNamed:#"SegmentUnselectedBG"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
UIImage *segmentSelectedBG = [[UIImage imageNamed:#"SegmentSelectedBG"] resizableImageWithCapInsets:UIEdgeInsetsMake(4, 4, 4, 4)];
UIImage *segmentDividerNoSelect = [[UIImage imageNamed:#"SegmentDividerNoSelect"] resizableImageWithCapInsets:UIEdgeInsetsMake(3, 3, 3, 3)];
UIImage *segmentDividerLeftSelect = [[UIImage imageNamed:#"SegmentDividerLeftSelect"] resizableImageWithCapInsets:UIEdgeInsetsMake(4, 4, 4, 3)];
UIImage *segmentDividerRightSelect = [[UIImage imageNamed:#"SegmentDividerRightSelect"] resizableImageWithCapInsets:UIEdgeInsetsMake(4, 3, 4, 4)];
UIImage *segmentDividerBothSelect = [[UIImage imageNamed:#"SegmentDividerBothSelect"] resizableImageWithCapInsets:UIEdgeInsetsMake(4, 4, 4, 4)];
[self.programControlsSegment setBackgroundImage:segmentUnselectedBG forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.programControlsSegment setBackgroundImage:segmentSelectedBG forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[self.programControlsSegment setDividerImage:segmentDividerNoSelect forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.programControlsSegment setDividerImage:segmentDividerLeftSelect forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.programControlsSegment setDividerImage:segmentDividerRightSelect forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[self.programControlsSegment setDividerImage:segmentDividerBothSelect forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
Neither segment selected, appearance is correct:
Left Segment selected, appearance is correct:
Left segment selected, and user pressing on the left segment, appearance is incorrect
Left segment selected, and user pressing on right segment, appearance is incorrect
Right segment is selected, and user is pressing on left segment, appearance is incorrect
Are there other segment states that I should be setting the divider image for?
EDIT:
This issue seems to be isolated to behavior only in iOS 7. Prior to this version, there did not seem to be a different state for the segments for when the user is actively pressing down on the segment
Related
In this photo (AirBnB iOS app), where it saids Upcoming and Previous, what do you guys think how this is implemented? Do you guys think this is developed using segmented control or two different buttons reversing (on/off, off/on) each other?
Is there an easy way(preferably using Swift) or a library to implement this feature in the app?
Sorry if this is a very naive question. It's my 3rd day learning iOS development :Face With Tears Of Joy:
Yes, it's probably a segmented control. You can having something like the following:
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];
Quoted from RayWenderlich:
http://www.raywenderlich.com/21703/user-interface-customization-in-ios-6
There is no right answer since we don't have the source code.
However it could be one of those proposition :
Using a UISegmentedControl and customize it's appearance ;
Using two UIButton and change there appearance depending on which one is currently selected ;
Creating your own component : IBDesignable (that you'll be able to see directly while building your interface).
Since you are at your 3rd day learning iOS development, you might want to give a look at all the proposition above.
The IBDesignable solution could be the better one. Indeed, if you build it properly you would be able to reuse it easily on different screen size and in multiple apps. But, it might not be easy for you to create it in the first place.
Is there a way in iOS 7 to completely remove the outer frame of an UISegmentedControl? There should be only one rectangle in tint color for the selected segment.
First, create three images and add them your your Image Assets.
Blank (a transparent png of any size)
Highlight (a png of any color and size)
Select (a png of any color and size)
Then add this code:
UIImage *backgroundImage = [UIImage imageNamed:#"Blank"];
UIImage *highlightedImage = [UIImage imageNamed:#"Highlight"];
UIImage *selectedImage = [UIImage imageNamed:#"Select"];
UIImage *dividerImage = [[UIImage alloc] init];
[segmentedControl setBackgroundImage:backgroundImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[segmentedControl setBackgroundImage:highlightedImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[segmentedControl setBackgroundImage:selectedImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[segmentedControl setDividerImage:dividerImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal 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 am custumizing all segmented controls in my app with the following code.Initially I set the selected segment to index 2.
Everything works perfect in IOS 6.While I was testing the app on IOS5, I realised that the initial setting of segmented control had a bug.The separation image between selected and unselected state is not set right.Due to that it looks like this.
If i change the selected segments by tapping the segmentedcontrol behaves normal.It is very weird.What elsse shall i do to prevent this strange behaviour?
UISegmentedControl *localSegmentedControl = [[UISegmentedControl alloc] init];
if ([localSegmentedControl respondsToSelector:#selector(setBackgroundImage:forState:barMetrics:)]) {
UIImage *segmentUnselectedSelectedDivider = [UIImage imageNamed:#"segmentedControlSeperatorNS.png"];
UIImage *segmentSelectedUnselectedDivider = [UIImage imageNamed:#"segmentedControlSeperatorSN.png"];
UIImage *segmentUnselectedUnselectedDivider = [UIImage imageNamed:#"segmentedControlSeperatorNN.png"];
UIImage *segmentUnselected = [[UIImage imageNamed:#"barButtonPlain.png"] stretchableImageWithLeftCapWidth:7 topCapHeight:0];
UIImage *segmentSelected = [[UIImage imageNamed:#"doneButton.png"] stretchableImageWithLeftCapWidth:7 topCapHeight:0];
[[UISegmentedControl appearance] setBackgroundImage:segmentUnselected
forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setBackgroundImage:segmentSelected
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedUnselectedDivider
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentSelectedUnselectedDivider
forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[[UISegmentedControl appearance] setDividerImage:segmentUnselectedSelectedDivider
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
}
After trying all relevant approached explained in Customizing UISegmentedControl in iOS 5
i figured out that the problem is related with the width of the separation line.The tutorial about segmented control customisation in http://www.raywenderlich.com/4344/user-interface-customization-in-ios-5 assumes that the separation images are wider than 2px (in Retina).
I made them exactly 2px wide and the problem is resolved.
I think it is a known bug.
It is the same here with a workaround, may work for you.
Customizing UISegmentedControl in iOS 5
When i use segment control I was very tired the same problem. I solved that code
UIImage *segmentSelected =
[[UIImage imageNamed:#"ikisiSecildiKirmizi.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 5, 15)];
UIImage *segmentUnselected =
[[UIImage imageNamed:#"ikisiSecilmediGri.png"]
resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 5, 15)];
UIImage *segmentSelectedUnselected =
[[UIImage imageNamed:#"solSecili.png"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 5, 15)];
UIImage *segUnselectedSelected =
[[UIImage imageNamed:#"sagSecili.png"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 5, 15)];
UIImage *segmentUnselectedUnselected =
[[UIImage imageNamed:#"ikisideSecilmemis.png"]resizableImageWithCapInsets:UIEdgeInsetsMake(0, 15, 5, 15)];
[fiyatSaat setBackgroundImage:segmentUnselected
forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[fiyatSaat setBackgroundImage:segmentSelected
forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[fiyatSaat setDividerImage:segmentUnselectedUnselected
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[fiyatSaat setDividerImage:segmentSelectedUnselected
forLeftSegmentState:UIControlStateSelected
rightSegmentState:UIControlStateNormal
barMetrics:UIBarMetricsDefault];
[fiyatSaat setDividerImage:segUnselectedSelected
forLeftSegmentState:UIControlStateNormal
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
NSDictionary *attributes = [NSDictionary dictionaryWithObject:[UIColor blackColor]
forKey:UITextAttributeTextColor];
[fiyatSaat setTitleTextAttributes:attributes
forState:UIControlStateNormal];
NSDictionary *attributes2 = [NSDictionary dictionaryWithObject:[UIColor whiteColor]
forKey:UITextAttributeTextColor];
[fiyatSaat setTitleTextAttributes:attributes2
forState:UIControlStateHighlighted];
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];