iOS - UISegmentedControl Strange Behaviour - ios

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];

Related

tvos UISegmentedControl focus style not change

I want to change background color of UISegmentedControl when it highlighted in tvOS.
Normally Segment display like following.
When change focus for change selected segment at that time display like following.
How to change white background when UISegmentedControl focused?
I was try following things but not working.
1) create custom class of UISegmentedControl and do following code in awakeFromNib
[self setBackgroundImage:image forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self setBackgroundImage:image forState:UIControlStateFocused barMetrics:UIBarMetricsDefault];
2) override setHighlighted method of UISegmentedControl
3) change background color in didUpdateFocusInContext method.
From my understanding of your question, you want to change the background color same as UISegmentControl tint color. What you need to do is simply use this:
label.backgroundColor = segmentedControl.tintColor;
Hope this will help you if not try this:
You just need to give its background color to clear from storyboard. This is happening due to default background selection and default selection is as per theme. Once you set the segmentControl background color to clear you will get the required result.
Or you can do:
Try to set your UISegmentcontrol background color to clear in viewDidLoad, you will get your result. I have tried this and it worked for me.
segment.backgroundColor = Color.clear;
its easy to clear the background color of segment control:
yourSegment.backgroundColor = .clear

TintColor Changing on Popover Push

I'm setting the tint color of a window to an arbitrary color, then trying to over-ride this on a per-button basis, but it appears that the buttons revert to the window tint color whenever there is a segue applied on them.
Setting tint color in didFinishLaunchingWithOptions:
self.window.tintColor = [UIColor redColor];
and then my two buttons in viewDidLoad:
[self.button1 setImage:[[UIImage imageNamed:#"711-trash"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate] forState:UIControlStateNormal];
self.button1.tintColor = [UIColor purpleColor];
self.button2.tintColor = [UIColor blueColor];
where button1 is a custom type button and button2 is a system type button.
When the popover first presents, the two buttons are tinted purple and blue. But when the segue view controller is pushed, the popped, the two buttons switch to red. Is there any way to prevent this?
EDIT:
I've tried reproducing your code like this:
However everything worked as expected:
So I agree with #user3779315, possibly you are setting the buttons' tint color somewhere else. Btw, additional code of your project would help to clarify the issue :-)

iOS 7 : Disable UINavigationBar Translucency For Entire App

Is there a way to disable UINavigationBar Translucency for an entire application?
I'm aware that using [self.navigationController.navigationBar setTranslucent:NO] can fix this issue for a single controller, but I have a lot of UINavigationBars in my application and this is a pretty tedious solution.
I've tried [[UINavigationBar appearance] setTranslucent:NO], but that functionality is surprisingly not supported. Doing that results in Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** Illegal property type, c for appearance setter, _installAppearanceSwizzlesForSetter:'
If I HAVE to, I can go through my entire app setting UINavigationBars to disable translucency one by one, but there must be some more elegant solution to this issue...
if you set the translucence of the first navigation bar in the stack to false [self.navigationController.navigationBar setTranslucent:NO], it will reflect in all the following NavigationViewController that are pushed to that stack.
Here is a Swift solution if you want to apply this Styling to the whole app.
in the AppDelegate class add this to the didFinishLaunchingWithOptions:
For Swift 2:
UINavigationBar.appearance().translucent = false
For Swift 3+:
UINavigationBar.appearance().isTranslucent = false
It seems very simple with this code in appDelegate didFinishLaunchingWithOptions (works fine with iOS 8 and above versions)
[[UINavigationBar appearance] setTranslucent:NO];
I think you are right about no appearance proxy being available for this property. Are you using UINavigationControllers or UINavigationBar objects? If you are using UINavigationBars you could subclass it and create a non-translucent nav bar.
Header file:
#import <UIKit/UIKit.h>
#interface ABCNonTranslucentNavBar : UINavigationBar
#end
Implementation file:
#import "ABCNonTranslucentNavBar.h"
#implementation ABCNonTranslucentNavBar
- (void)drawRect:(CGRect)rect
{
[self setTranslucent:NO];
}
Then just replace the UINavigationBars with your subclass. You could also do something similar with a subclassed UINavigationController.
Adding this in case anyones still battling this.
You can fool it though by specifying a non exist image, which will make the nav bar INCLUDING it's tool bar go opaque
[[UIToolbar appearance] setBackgroundColor:[UIColor colorWithRed:219.0/255.0 green:67.0/255.0 blue:67.0/255.0 alpha:1.0]];
[[UIToolbar appearance] setBackgroundImage:[[UIImage alloc] init] forToolbarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
I know this is old, but this might come in handy for someone;
You can use a category, and within it* set the property [translucent][1]
#implementation UINavigationBar (MakeTranslucent)
-(void)willMoveToWindow:(UIWindow *)newWindow {
[super willMoveToWindow:newWindow];
self.translucent = NO;
}
#end
I used willMoveToWindow, I do not know whether this is a good idea so UAYOR.
See the excerpt from UIKit code documentation:
/*
New behavior on iOS 7.
Default is YES.
You may force an opaque background by setting the property to NO.
If the navigation bar has a custom background image, the default is inferred
from the alpha values of the image—YES if it has any pixel with alpha < 1.0
If you send setTranslucent:YES to a bar with an opaque custom background image
it will apply a system opacity less than 1.0 to the image.
If you send setTranslucent:NO to a bar with a translucent custom background image
it will provide an opaque background for the image using the bar's barTintColor if defined, or black
for UIBarStyleBlack or white for UIBarStyleDefault if barTintColor is nil.
*/
Correct Swift 4 solution is
UINavigationBar.appearance().isTranslucent = false
UINavigationBar.appearance().backgroundColor = .white
I think appearance api does not support translucent property of navigation bar .
But you can do this for whole App like this , please have a look at this code --
here Menu Screen is a root view controller .
MenuScreen *ms = [[MenuScreen alloc]initWithNibName:#"MenuScreen" bundle:nil];
UINavigationController *nv = [[UINavigationController alloc]initWithRootViewController:ms];
//This will set property for whole App.
[nv.navigationBar setTranslucent:NO];
self.window.rootViewController = nv ;
If you don't use storyboard, but IB, set the navigation bar style of your MainWindows.xib to NOT translucent and set as color not the clear color.

UISegmentedControl does not respect divider images set for UIControlStateDisabled

I'm using the new UIAppearance API in iOS 5 to style a UISegmentedControl with custom graphics. I need to be able to set some segments to be disabled at times during execution, but the UIAppearance methods don't seem to allow me to set a divider image for the UIControlStateDisabled state.
I'm calling:
[[UISegmentedControl appearance] setDividerImage:disabledSelectedImage
forLeftSegmentState:UIControlStateDisabled
rightSegmentState:UIControlStateSelected
barMetrics:UIBarMetricsDefault];
where disabledSelectedImage is a resizable image from this resource:
Yet when I set the left segment to be disabled ([UISegmentedControl setEnabled:forSegmentAtIndex:]), the result is this:
You can clearly see that the UISegmentedControl has defaulted to use the UIControlStateNormal-UIControlStateNormal divider image.
It seems perfectly happy for me to set a background image using UIControlStateDisabled
[[UISegmentedControl appearance] setBackgroundImage:disabledImage
forState:UIControlStateDisabled
barMetrics:UIBarMetricsDefault];
(and respects the image I supply while in the disabled state) but not a divider image. Has anyone come across this or found a solution?
I've decided that this must be an iOS bug and have filed a radar with Apple. My solution to the problem for now is to remove segments, rather than disabling them.
A bit of an ugly workaround but i managed to fix it with the following until apple fixes it itself.
First you need to subclass UISegmentedControl and add the following:
#implementation MJSegmentedControl
- (void)layoutSubviews
{
[super layoutSubviews];
NSInteger cachedIndex = self.selectedSegmentIndex;
self.selectedSegmentIndex = 0;
self.selectedSegmentIndex = cachedIndex;
}
#end
I haven't had a need to use the appearance controls of iOS 5 yet but if all else fails you could add the resizable image as a child of the segmented control to cover up the ugliness. It's a hack, but it may work and will be relatively forwards-compatibile. Just be certain to set the autosizing masks appropriately.
I had the same issue and it really seems to be a bug. However I've found a solution (a workaround).
I've used XIB file with a controller. In XIB file segmented control was just placed and all of the customisations were done in -viewDidLoad method.
Then I've created a UIView subclass which represented entire view in the XIB. It made possible moving all view customisation code to the -awakeFromNib method of this UIView subclass. After moving this code the divider images were set properly.
As suggested by Fernando in this thread:
Customizing UISegmentedControl in iOS 5
You can try to dispatch your UISegmentedControl settings on the main queue via:
dispatch_async(dispatch_get_main_queue(),^{
// disable part of the segmented control
[self.eventScopeSegmentedControl setEnabled:NO forSegmentAtIndex:2];
});
I did this in viewDidLoad and it worked fine for a while but when my app is really busy at startup, this doesn't always work. I'm guessing there's a race condition that may still revert any settings you made when the appearance proxy goes to work.
I added another ugly hack to make this call in viewWillAppear (after the call to super:viewWillAppear) with a flag (set from viewWillLoad) to ensure this only runs once.
There is actually a pretty simple way to get this done. The current behavior is obviously a bug so this is not an ideal solution but simply a workaround that works beautifully. Namely, use an additional UIView as a "disabled visual cue".
The general steps:
Add a UIView as a sibling to the UISegmentedControl. Ensure the UIView is in front of the UISegmentedControl
Apply the desired color and a transparency to the UIView to match your app skin
Move the UIView to be exactly on top of the UISegmentedControl
Shape the UIView to have the exact size top of the UISegmentedControl
Apply a rounded corner to the UIView to mirror the exact shape of the UISegmentedControl
When the UISegmentedControl is supposed to be disabled, simply show the UIView and disable the user interaction on the UISegmentedControl.
When the UISegmentedControl is supposed to be enabled, simply hide the UIView and enable the user interaction on the UISegmentedControl.
In both cases do not change the UISegmentedControl.enabled property.
Note that it seems like a lot of steps but all of this can be coded in so to add support for disabling your custom UISegmentedControl becomes pretty much a 1 liner after you add this to a configure segmented control method.
Here is how my custom segmented control looks when applying this solution:
Enabled Segmented Control
"Disabled" Segmented Control
Here are some code snippets of interest:
Shape the UIView to match the UISegementedControl (load time configuration)
UISegmentedControl* segmentedControl = ...
//Segmented Control disabled visual cue view
UIView* view = ...
//Step #2
view.backgroundColor = [[UIColor whiteColor] colorWithAlphaComponent:0.6];
//Step #3 and #4
view.frame = segmentedControl.frame;
//Step #5
view.layer.cornerRadius = 5
view.clipsToBounds = YES;
//Ensure this is disabled by default
view.userInteractionEnabled = NO;
Enable/"Disable" UISegementedControl (runtime state change)
BOOL segmentedControlEnabled = ...
if(segmentedControlEnabled) {
segmentedControl.userInteractionEnabled = YES;
view.hidden = YES;
} else {
segmentedControl.userInteractionEnabled = NO;
view.hidden = NO;
}
That's it.
-

Scope Bar for UITableView like App Store?

Does anyone know how to add a scope bar to a UITableView?
The App Store app does this sometimes, like in the picture below.
I would like to use this scope bar to add sorting options for the elements in the UITableView. This would be more convenient than having a toolbar with a UISegmentControl.
I just don't know how to implement this. I don't even know the name of the element (I'm calling it scope bar because it looks just like the scope bar of a UISearchBar, but it is not).
Actually, unlike what others have said, this UISegmentedControl's .segmentedControlStyle property is set to an undocumented value of 7.
theSegCtrl.segmentedControlStyle = 7;
But #Macatomy's answer is more AppStore-safe (although Apple can't detect this anyway).
Probably you already solved this issue but I believe this can be helpful for other people.
Inside your ViewController that you use in that TableViewController, you should insert the following code:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
NSArray *segmentTextContent = [NSArray arrayWithObjects: #"one",#"two",#"three", nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:segmentTextContent];
segmentedControl.frame = CGRectMake(2, 5, 316, 35);
[self.segmentedControl addTarget:self action:#selector(segmentChanged:) forControlEvents:UIControlEventValueChanged];
self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; //changes the default style
self.segmentedControl.tintColor = [UIColor darkGrayColor]; //changes the default color
self.segmentedControl.enabled = true;
self.segmentedControl.selectedSegmentIndex = 0;
return self.segmentedControl;
}
That inserts a segmented control as the table header, which (if you wish) will also bounce when you reach the list top and at the same time will always remain visible while you scroll in your list.
Hope it helps.
The element is a UISegmentedControl with the UISegmentedControlStyleBar style. You can set the tintColor property to get the color desired. Just put the view above the table view and you can get something that looks like that screenshot.
UISegmentedControl
You create it, set up its segments, and set its delegate. The delegate then takes some sort of action every time the selected segment changes.

Resources