How to properly utilize UISegmentedControl? - ios

I am new to iOS development and would like to know the proper way to implement a UISegmentedControl.
I've dragged out the segment, dropped it where I want, changed its tint color via the attributes in the sidebar, then changed the text of each segment. I then held control and dragged to ViewController.m to create an outlet. Here's that function:
- (IBAction)touchSegment:(UISegmentedControl *)sender {
NSString *selectedSegmentTitle = [sender titleForSegmentAtIndex:sender.selectedSegmentIndex];
if ([selectedSegmentTitle isEqualToString:#"2 cards"]) {
NSLog(#"first tapped");
}
else if ([selectedSegmentTitle isEqualToString:#"3 cards"]) {
NSLog(#"second tapped");
}
}
This is intuitive, but it's not working properly. While the attributes in XCode all state I've set a custom tint color (selected the segment as a whole, then double clicked each individual one), only the left segment is tinted when launching the app - the border of the right is still the default blue. If in iOS Simulator I click the right segment then the color is changed to the correct set tint. I've also set which one should be selected by default in the sidebar, yet it doesn't show that in the storyboard. Not sure if I've done it right and these are minor bugs in XCode or if I've missed something or done it wrong in the first place.
Xcode storyboard:
iOS Simulator upon launch:
I'm running Xcode 5.0.2 and the iOS Simulator v7.0.3. Thanks!

That is the way that the tint color works in iOS 7. You can customize your control further by using the function
[control setBackgroundImage: forState: barMetrics:]
you could call it like so -
[control setBackgroundImage:unselectedBackImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[control setBackgroundImage:selectedBackgroundImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];

Related

Segment Bar in iOS accross different Size classes

I'm using UISegmentController (default provided by iOS). I want to show text for iPad or iPhone landscape view. Where as in case of iPhone, I want to show icons (not text) in the same segment bar.
Is it possible? If yes, then how can I achieve this in story board or programmatically?
You can achieve this by adding UISegmentedControl programatically.
Code is as follows in controller viewWillAppear method,
- (void)viewWillAppear:(BOOL)animated {
UISegmentedControl * cntrl = [[UISegmentedControl alloc] initWithItems:#[[UIImage imageNamed:#"Circle"],#"2"]];
cntrl.frame = CGRectMake(30, 100, 200, 50);
[self.view addSubview:cntrl];
}
With above code we're creating segment control with one image in first segment and text in second segment. Check attached screenshot.
Use following code to check either device is iPad or iPhone
-(BOOL) isiPad {
return UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad;
}
Based on the type of the device, customise segment control.
For existing segment control, when you want to set image,
[cntrl setImage:[UIImage imageNamed:#"Tick"] forSegmentAtIndex:0];
use above method by specifying which image you want to set at particular segmentIndex.
At the same way when you want to set text at particular index, use
[cntrl setTitle:#"Hello" forSegmentAtIndex:0];
It doesnt seem possible to use the storyboard completely on its own to do this kind of functionality, but a combination of this and this inside your viewDidLoad might get you want you want

Why are my UISegmentControl segments highlighting in iOS 8 when I have set background images for all states?

In iOS 6/7, I have used UISegmentedControl with background images to create an effect like so:
I accomplished this by setting the background image for the UISegmentedControl for each of standard states, like so:
UIImage *segmentedControlBackgroundImage = [UIImage imageNamed:#"profileSegmentedControlBackground"];
UIImage *segmentedControlBackgroundSelectedImage = [UIImage imageNamed:#"profileSegmentedControlBackgroundSelected"];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundImage forState:UIControlStateDisabled barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundSelectedImage forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundSelectedImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
When a segment becomes select or is highlighted, it has the nice blue bar underneath and I set text attributes to change the text color to be blue. There's some extra code for the dividers, but I think that's unrelated so I've omitted it.
My problem is that in iOS 8, there are a couple of actions that cause the background of the segment to turn gray and look bad; One being when you change your selection, the cell you tapped turns gray until the transition completes, and the other is that if you tap and hold an already selected segment, it turns gray. Both look identical and can be seen below.
Some extra pieces of possibly relevant information:
The tintColor for the segmentedControl is clear
I'm not subclassing UISegmentedControl
I haven't changed any properties for UISegmentedControl using its appearance proxy
I am using 1 point wide images for the background images and UISegmentedControl is automatically determining the capInsets and tiling the image
The reason the segment turns grey on selecting an already selected segment is because the segmented control is missing the state for selected and highlighted at the same time.
In your case calling:
[self.segmentedControl setBackgroundImage:segmentedControlBackgroundSelectedImage forState:UIControlStateSelected | UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
should fix that problem.
when you change your selection, the cell you tapped turns gray until
the transition completes
I couldn't reproduce that one, but perhaps this will fix both issues.
Just in case, in Swift that would be (UPD for Swift 4)
segmentedControl.setBackgroundImage(image, forState: .selected, barMetrics:.Default)
segmentedControl.setBackgroundImage(image, forState: .highlighted, barMetrics:.Default)

iOS - UISegmentedControl Strange Behaviour

I have added a UISegmentedControl in the application. The segment control works fine and all i am doing with it is to get its selected state when a value is changes nothing else.
The UISegmentedControl initially looks like this
-
After i show an Reachability Not available state it looks like this
-
But after the application resumes and internet is connected and application resigns active it looks like this
The UISegmentedControl does work properly but the color does not resume its state.
- The Reachibility blocks are in Application Delegates and have nothing to do with the UISegmentControl
EDIT
I have also checked that even after i set the color programatically in
viewDidLoad or viewDidAppear or even in the state changed setting the
TintColor of the UISegmentedControl it insted of an RGBA value it
gives color as ( UIDeviceWhiteColorSpace 0.3 0.8 )
I had a similar problem.. This helped me
You can give it a try
self.segControl.tintAdjustmentMode = UIViewTintAdjustmentModeNormal;
this kind of acts like a refresh (what i call it) for the segment control
I had placed this in -(void)viewWillAppear:(BOOL)animated . You can place it in the same method or a method where the control would return after the networking call and alert is dismissed.
Hope this helps.
Use break points to find the solution and then check whether the alpha colour has changed before and after internet connection. Or better you set tint appearance something like this..
#pragma mark - Appearance Methods
-(void)customizeAppearance {
UIColor *appTintColor = [UIColor colorWithRed:20/255.0f green:160/255.0f blue:160/255.0f
alpha:1.0f];
[[UISearchBar appearance] setBarTintColor:appTintColor];
[[UISegmentedControl appearance] setTintColor:appTintColor];
self.window.tintColor = [UIColor colorWithRed:10/255.0f green:80/255.0f blue:80/255.0f
alpha:1.0f];
}
I have got the same situation in my app.
I tried all the appearance methods but nothing seems to work. Instead it is all about showing the alertview at the right place. The alertview when shown causes the os to set the tintcolor to gray to the all items in the current viewcontroller. If when shown on viewcontroller launch there will be a conflict on which viewcontroller the tintcolor is changed. I guess this is causing the color change bug.
I guess you would have checked the reachability in you viewwillappear and you would have shown the alertview in the viewwillappear method. Instead have a bool value and set is as YES or NO depending on the values and then show the alertview of the internetconnection on viewdidappear by checking the bool value.
This is how i solved mine.
Instead of setting the color on interface builder try setting it programatically for the component.
Doing it this way will allow to to use breakpoints to check exactly what is happening after the Reachability notification is done.
You can simply call it on the constructor, for example:
[UIColor colorWithRed:66.0f/255.0f green:79.0f/255.0f blue:91.0f/255.0f alpha:1.0f]
[[UISegmentedControl appearance] setTintColor:appTintColor];
Perhaps you could re-confirm all tintsettings programmatically in the reachability's notification receiver?
-(void)reachabilityChanged:(NSNotification*)note
{
Reachability * reach = [note object];
//set tints and colors either way (isReachable and !isReachable)
}
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(reachabilityChanged:)
name:kReachabilityChangedNotification
object:nil];
Remember that UIView in iOS 7 has a tintAdjustmentMode property.
In your case, this property has probably been set on your UISegmentedControl to UIViewTintAdjustmentModeDimmed when the screen was dimmed.
From the documentation of UIView:
If the view’s tintAdjustmentMode property’s value is
UIViewTintAdjustmentModeDimmed, then the tintColor property value is
automatically dimmed.
You must set the divider image whose height and width should be same as the height of segment control, divided into two halves red and blue in your case
use the following code:
[segmentControllerObj setDividerImage:[UIImage imageNamed:#"left.png"] forLeftSegmentState:UIControlStateSelected rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[segmentControllerObj setDividerImage:[UIImage imageNamed:#"right.png"] forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateSelected barMetrics:UIBarMetricsDefault];

Incorrect tint for selected segment of UISegmentedControl on iOS 7

I have a UISegmentedControl in a UIToolbar with custom background/divider images. Through iOS 6 this displayed correctly, but as of iOS 7 the selected segment is showing the foreground image for that segment as a cutout (revealing the toolbar underneath) rather than the white the other segments are showing as.
Any ideas on if there's just something I'm missing to make it behave as expected?
Before anyone says it, I am not going to use the default iOS 7 UISegmentedControl appearance since I find it hideous.
Nevermind. I figured it out shortly after posting.
UISegmentedControl interprets its images as being in rendering mode UIImageRenderingModeAlwaysTemplate unless otherwise specified.
I had to use - [UIImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] on each segment's image for iOS 7 to achieve the previous behavior.
Use this code to set image on Segment Control in iOS 7 with xCode 5
if ([UIImage instancesRespondToSelector:#selector(imageWithRenderingMode:)]) {
[segmentControl setImage:[[UIImage imageNamed:#"image.png"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forSegmentAtIndex:0];
}
else {
[segmentControl setImage:[UIImage imageNamed:#"image.png"] forSegmentAtIndex:0];
}

UIButton and selected highlight state

The UIButton has a normal/default, highlighted, and selected image. I then have a IBAction method that is called on Touch Down. The method changes the highlighted image depending if it's selected. But when the button is selected, the method is called and so the highlight image is changed, however what is displayed is the normal/default image with a tint. I have tested that image used is in not nil. What happens is when the UIButton in a selected state is pressed displays the normal state with a tint. Why is it not using the highlight image and is there another way of showing a selected highlight image?
Why do you set the highlighted state in the IBAction method? You only need to set the highlighted image for you button when you create it. It will switch automatically. Adding a tint when selected is the default behavior of 'selection' when no highlighted image is assigned.
if your using Interface Builder, just assign the highlighted image there.
Im assuming your looking for normal button selection behavior with your IBAction method set to the touchUpInside event.
I got around this problem by using the selected state and notifications (not via the UI). When a notification is called I change image for the default state, change the selected state and then change the image for selected state.
Update:
I came up with a much better idea from another question that was doing something similar to me. The way to do it is to things in setSelected
- (void)setSelected:(BOOL)selected
{
if ( selected )
{
[self setImage:[CFCHStyleSheet imageForTickButtonChecked] forState:UIControlStateNormal];
[self setImage:[CFCHStyleSheet imageForTickButtonChecked] forState:UIControlStateSelected];
[self setImage:[CFCHStyleSheet imageForTickButtonCheckedDisabled] forState:UIControlStateDisabled];
}
else
{
[self setImage:[CFCHStyleSheet imageForTickButtonUnchecked] forState:UIControlStateNormal];
[self setImage:[CFCHStyleSheet imageForTickButtonUnchecked] forState:UIControlStateSelected];
[self setImage:[CFCHStyleSheet imageForTickButtonUncheckedDisabled] forState:UIControlStateDisabled];
}
[super setSelected:selected];
}

Resources