UIActivityIndicatorView ignores color property - ios

Here is my code for initializing UIActivityAndicatorView:
self.indicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge];
self.indicator.color = [UIColor colorWithRed:252.0 green:113.0 blue:9.0 alpha:1.0];
self.indicator.center = self.view.center;
[self.view addSubview:self.indicator];
After animation started - indicator appears in proper place, but with white color. Why color property is ignored?

The values are floats between 0 and 1. Try this:
self.indicator.color = [UIColor colorWithRed:252.0/255.0 green:113.0/255.0 blue:9.0/255.0 alpha:1.0];

It's important to notice that the activityIndicatorViewStyle will override the color property as per the documentation:
If you set a color for an activity indicator, it overrides the color provided by the activityIndicatorViewStyle property.
So you just have to set the style first, then the color:
let activityIndicator = UIActivityIndicatorView()
activityIndicator.activityIndicatorViewStyle = .whiteLarge
let myColor = UIColor.colorWithRed(252.0/255.0, green: 113.0/255.0, blue: 9.0/255.0, alpha: 1.0)
activityIndicator.color = myColor
activityIndicator.startAnimating()
And that should be it.

I'm amazed that the selected answer worked in Dec of 2015, since I cannot get the color to show anything but white no matter what I do in iOS 9.2. This for the Large White spinner.
What I did find that works is to start the control with an alpha of 0, then after a 100 milliseconds change the color and show it. The code below is from my ATMHud fork on github:
- (void)setActivity:(BOOL)activity
{
hudView.showActivity = activity;
if (activity) {
[hudView.activity startAnimating];
hudView.activity.alpha = 0;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.1 * NSEC_PER_SEC), dispatch_get_main_queue(), ^
{
// Workaround for bug where Apple ignores the color property
[self changeColor];
} );
} else {
[hudView.activity stopAnimating];
}
}
- (void)changeColor
{
hudView.activity.color = [UIColor blackColor];
[UIView animateWithDuration:.250+_animateDuration animations: ^{ hudView.activity.alpha = 1; }];
}

Related

How to make semi-transparent button with shadow?

I have a UIButton, that needs to be white and 50% transparent. In the same time I need shadow. But shadow is a rectangle and it could be seen through button background. Is it possible to make something with that?
The code I have now:
self.WhiteBtn.backgroundColor = [UIColor colorWithRed:255 green:255 blue:255 alpha:0.9];
self.WhiteBtn.opaque = NO;
self.WhiteBtn.clipsToBounds = NO;
self.WhiteBtn.layer.shadowColor = [UIColor blackColor].CGColor;
self.WhiteBtn.layer.shadowOpacity = 0.5;
self.WhiteBtn.layer.shadowRadius = 5;
self.WhiteBtn.layer.shadowOffset = CGSizeMake(0,0);
There were 2 initial problems: the shape of the shadow (which was rectangular initially) and the button background color being blended with the shadow color. Also, the UIColor initializer accepts all the arguments in range [0.0, 1.0]. Finally, I made some more tweaks and got this (see both the code and a sample button below).
Code:
let shadowPathWidth: CGFloat = 1.0 // fine tune your shadow's width with this
let layerAndShadowRadius: CGFloat = 5.0 //and its radius with this
WhiteBtn.backgroundColor = UIColor(red:1, green:1, blue:1, alpha:0.9)
WhiteBtn.layer.cornerRadius = layerAndShadowRadius
WhiteBtn.layer.shadowPath = CGPathCreateCopyByStrokingPath(CGPathCreateWithRoundedRect(WhiteBtn.bounds, layerAndShadowRadius, layerAndShadowRadius, nil), nil, shadowPathWidth, CGLineCap.Round, CGLineJoin.Bevel, 0.0)
WhiteBtn.layer.shadowOpacity = 1.0;
WhiteBtn.layer.shadowOffset = CGSizeMake(0,0)
Sample button:

How to check if a UIView's backgroundColor is clearColor?

This doesn't work:
if([myView.backgroundColor isEqual:[UIColor clearColor]])
NSLog("Background is clear");
else
NSLog("Background is not clear");
P.S: To reproduce the case, drag a uiview in interface builder, set it's background color to clear color from interface builder. Set an outlet of the view, then compare it in viewDidLoad using the code above.
Here is the link of the test project: https://drive.google.com/file/d/0B_1hGRxJtrLjMzUyRHZyeV9SYzQ/view?usp=sharing
Here is the Snapshot of Interface Builder:
Maybe both colors are clear but still not the same? It's not enough that the alpha value is the same...
UIColor.clearColor() == UIColor(white: 1.0, alpha: 0.0) // false
UIColor.clearColor() == UIColor(white: 0.0, alpha: 0.0) // true
Try
if([myView.backgroundColor isEqual:[UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0]])
NSLog("Background is clear");
else
NSLog("Background is not clear");
Even better is probably to just check if the alpha is 0.0:
CGFloat alpha = CGColorGetAlpha(myView.backgroundColor.CGColor);
if( alpha == 0.0 )
NSLog("Background is clear");
else
NSLog("Background is not clear");
You code is correct
UIView *aView = [[UIView alloc] init];
aView.backgroundColor = [UIColor clearColor];
if([aView.backgroundColor isEqual:[UIColor clearColor]]) {
NSLog(#"Background is clear");
} else {
NSLog(#"Background is not clear");
}
Result:
2015-07-22 15:22:57.430 APP[1568:24173] Background is clear
UPDATE: case of default color from Interface builder
From : UIView Class Reference
#property(nonatomic, copy) UIColor *backgroundColor
Discussion
Changes to this property can be animated. The default value is nil,
which results in a transparent background color.
if you set color to be default from interface builder backgroundColor property will be nil so the comparison to [UIColor clearColor] will be false.
you can update you code the handle this case:
if([self.aView.backgroundColor isEqual:[UIColor clearColor]] || self.aView.backgroundColor == nil) {
NSLog(#"Background is clear");
} else {
NSLog(#"Background is not clear");
}
UPDATE: case of clear color from Interface builder
You can test the alpha value :
CGFloat bgColorAlpha = CGColorGetAlpha(self.aView.backgroundColor.CGColor);
if (bgColorAlpha == 0.0){
NSLog(#"clear ");
}else{
NSLog(#"not clear ");
}
2015-07-22 16:56:23.290 APP[1922:38283] clear
More information:
How to compare UIColors
Comparing colors in Objective-C
UIColor comparison
Your code is correct, you are just having an incorrect assumption. Run these lines to see where you're going wrong:
NSLog("view color: %#", myView.backgroundColor);
NSLog("expected color: %#", [UIColor clearColor]);

Switches and Ifs

I've got a slider that changes blur radius:
- (IBAction)sliderValueChangesFinderUp:(id)sender {
_sliderValue = round(self.blurSlider.value);
_effectImage = nil;
_effectImage = [BlurFilter imageByApplyingClearEffectToImage:self.myImage
withRadius:_sliderValue color:[UIColor colorWithRed:0 green:0 blue:0 alpha:0]];
self.imageView.image = _effectImage;
}
also I've got a button which should change blur color (the part - [UIColor colorWith..])
- (IBAction)setColorGreen:(id)sender {
_effectImage = nil;
_effectImage = [BlurFilter imageByApplyingClearEffectToImage:self.myImage
withRadius:_sliderValue color:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.15]];
self.imageView.image = _effectImage;
}
This button change the color, but when I want to change blur radius the color is resetted , I know that this is because of the code in - (IBAction)sliderValueChangesFinderUp:(id)sender.
But how should I create a switch or if correctly so when the button green is pressed blur color changes and I may change blur radius without resseting a color?
Keep a class level variable for UIColor, for example named colorObject. In your function - (IBAction)sliderValueChangesFinderUp:(id)sender access that variable and set it in your line
_effectImage = [BlurFilter imageByApplyingClearEffectToImage:self.myImage
withRadius:_sliderValue color:colorObject];
instead of creating a new one from scratch.
In you function - (IBAction)setColorGreen:(id)sender , modify that colorObject variable if you need to.
I believe what you're asking is that you'd like to change the color of the blur passed to imageByApplyingClearEffectToImage. A way to do this might be to move the code from the the control actions into a separate message. Both actions would call this message, but you could alter the color. Consider something like the following:
- (IBAction)sliderValueChangesFinderUp:(id)sender
{
_effectImage = [self blurImage:self.myImage
withColor:[UIColor colorWithRed:0 green:0 blue:0 alpha:0]];
self.imageView.image = _effectImage;
}
- (IBAction)setColorGreen:(id)sender
{
_effectImage = [self blurImage:self.myImage
withColor:[UIColor colorWithRed:0 green:1 blue:0 alpha:0.15]];
self.imageView.image = _effectImage;
}
- (UIImage *)blurImage:(UIImage *)image withColor:(UIColor *)color
{
return ([BlurFilter imageByApplyingClearEffectToImage:image
withRadius:_sliderValue
color:color]);
}
You're reusing code here by making the color a parameter instead of hardcoding it into a separate function.

Programatically change custom UiButton background color

Within my custom UIButton class called "ComingHomeButton", I'm not able to change the backgroundcolor
I would like to change it without creating images, but if it is the only way I will have to.
I also want to change the background color every time the button is tapped.
Here is what I have that doesnt work:
UIColor *color = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.5];
[self setBackgroundColor:color];
self refers to my "ComingHomeButton"
Thank you so much :-)
You can create a counter, and then loop through colors when a button is tapped:
-(IBAction)buttonTapped:(id)sender {
if (!counter) {
counter = 0
}
if (counter%3 == 0) {
self.backgroundColor = [UIColor redColor]; //or whatever custom color you want to use
} else if (counter%3 == 1) {
self.backgroundColor = [UIColor blueColor];
} else if (counter%3 == 2) {
self.backgroundColor = [UIColor greenColor];
}
counter++
}
and you can add as many colors as you want to loop through. The % denotes the mod function, making sure that when counter is bigger than 2, it will still return a number between 0 and 2.
The number after the % is the number of colors to loop through.
UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(50, 50, 300, 100)];
btn.backgroundColor = [UIColor blueColor];
[self.view addSubview:btn];
The following code works fine for adding a button the a given view with a background button. Try using the dot notation instead of the message pass.
-(IBAction)buttonTapped:(id)sender {
sender.backgroundColor = [self randomColor];
}
-(UIColor *)randomColor
{
CGFloat red = arc4random() % 255 / 255.0;
CGFloat green= arc4random() % 255 / 255.0;
CGFloat blue= arc4random() % 255 / 255.0;
UIColor *color = [UIColor colorWithRed:red green:green blue:blue alpha:1.0];
return color;
}
I did not test the code I am not on my mac but it should work.

Change the alpha value of the navigation bar

Is this possible?
I want to change the alpha value of the navigation bar in my view controller (in an animation), but if I do self.navigationController.navigationBar.alpha = 0.0;, the portion of the screen the navigationBar took up totally disappears and leaves a black box, which is not what I'd like (I'd prefer it to be the color of self.view's background).
As I support Colin's answer, I want to give you an additional hint to customize the appearance of an UINavigationBar including the alpha.
The trick is to use UIAppearance for your NavigationBar. This enables you to assign an UIImage to your NavigationBar's backgroundImage. You can generate these UIImages programmatically and use for that UIColors and set the colors' alpha properties as you want. I've done this in one of my own applications and it works as expected.
Here I give you some code snippets:
E.g. in your ..AppDelegate.m add these lines in didFinishLaunchingWithOptions:
//create background images for the navigation bar
UIImage *gradientImage44 = nil; //replace "nil" with your method to programmatically create a UIImage object with transparent colors for portrait orientation
UIImage *gradientImage32 = nil; //replace "nil" with your method to programmatically create a UIImage object with transparent colors for landscape orientation
//customize the appearance of UINavigationBar
[[UINavigationBar appearance] setBackgroundImage:gradientImage44 forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundImage:gradientImage32 forBarMetrics:UIBarMetricsLandscapePhone];
[[UINavigationBar appearance] setBarStyle:UIBarStyleDefault];
Implement convenience methods to programmatically creates UIImage objects, e.g. create a new category for UIImage:
//UIImage+initWithColor.h
//
#import <UIKit/UIKit.h>
#interface UIImage (initWithColor)
//programmatically create an UIImage with 1 pixel of a given color
+ (UIImage *)imageWithColor:(UIColor *)color;
//implement additional methods here to create images with gradients etc.
//[..]
#end
//UIImage+initWithColor.m
//
#import "UIImage+initWithColor.h"
#import <QuartzCore/QuartzCore.h>
#implementation UIImage (initWithColor)
+ (UIImage *)imageWithColor:(UIColor *)color
{
CGRect rect = CGRectMake(0, 0, 1, 1);
// create a 1 by 1 pixel context
UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
[color setFill];
UIRectFill(rect);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Re-work your image creation in 1. (#import "UIImage+initWithColor.h" in AppDelegate.m and replace the "nil"s):
This is your spot of interest: by changing your colors' alpha property you are influencing the opacity level of you NavigationBar as well!
UIImage *gradientImage44 = [UIImage imageWithColor:[UIColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:0.2]];
UIImage *gradientImage32 = [UIImage imageWithColor:[UIColor colorWithRed:1.0 green:0.0 blue:1.0 alpha:0.2]];
I created a small demo project and add you two screenshots:
the view itself has a yellow backgroundColor.
The backgroundImages of the NavigationBar have a red color.
Screenshot 1 shows a NavigationBar with a value for alpha = 0.2.
Screenshot 2 shows a NavigationBar with a value for alpha = 0.8.
The most straightforward way of doing this is modifying the alpha component of navigationBar background view, which at this time (iOS9) is a first navigationBar subview. Note however that we never know if the subview hierarchy will be changed by apple in later releases, so gotta be careful.
let navigationBackgroundView = self.navigationController?.navigationBar.subviews.first
navigationBackgroundView?.alpha = 0.7
Directly from the Apple Developer reference:
"there are only a handful of direct customizations you can make to the
navigation bar. Specifically, it is alright to modify the barStyle,
tintColor, and translucent properties, but you must never directly
change UIView-level properties such as the frame, bounds,
alpha, or hidden properties directly."
You can however set the translucence property of the navigation bar. If you do [self.navigationController.navigationBar setTranslucent:YES];
should solve your problem. You can also try seeing if any of the UIBarStyle enums are something you want.
MickBraun's answer in Swift:
In AppDelegate.swift add these lines in didFinishLaunchingWithOptions:
// create background images for the navigation bar
let gradientImage44 = UIImage.imageWithColor(UIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 0.2))
let gradientImage32 = UIImage.imageWithColor(UIColor(red: 1.0, green: 0.0, blue: 1.0, alpha: 0.2))
// customize the appearance of UINavigationBar
UINavigationBar.appearance().setBackgroundImage(gradientImage44, forBarMetrics: .Default)
UINavigationBar.appearance().setBackgroundImage(gradientImage32, forBarMetrics: .Compact)
UINavigationBar.appearance().barStyle = .Default
Implement convenience methods to programmatically create UIImage objects.
class func imageWithColor(colour: UIColor) -> UIImage {
let rect = CGRectMake(0, 0, 1, 1)
// Create a 1 by 1 pixel content
UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0)
colour.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
If you just want to get rid of the navigationBar in an animated way you could do:
[self.navigationController setNavigationBarHidden:YES animated:YES];
If you want to control the animation and its necessary to set the alpha to 0.0, read on:
The "black box" you are seeing is from the underlying view or window. If you just want your views color instead of the "black box" do:
self.navigationController.view.backgroundColor = self.view.backgroundColor;
[UIView animateWithDuration:1.0 delay:1.0 options:0 animations:^{
self.navigationController.navigationBar.alpha = 0.0;
} completion:NULL];
If you want your actual view to be where the navigationBar was, you need to increase the height of your view:
[UIView animateWithDuration:1.0 delay:1.0 options:0 animations:^{
self.navigationController.navigationBar.alpha = 0.0;
CGFloat navigationBarHeight = self.navigationController.navigationBar.frame.size.height;
CGRect frame = self.view.frame;
frame.origin.y -= navigationBarHeight;
frame.size.height += navigationBarHeight;
self.view.frame = frame;
} completion:NULL];
You have a few options depending, in part, upon the barStyle of your UINavigationBar. The main thing is realizing that you likely don't necessarily have to animate the alpha property to get the effect you're describing.
UIBarStyleDefault or UIBarStyleBlackOpaque Option A is to set your UINavigationBar translucent property to YES, then animate the alpha:
navigationBar.translucent = YES; // ideally set this early, in the nib/storyboard, or viewDidLoad
...
[UIView animateWithDuration: 1.0
animations: ^{
// toggle:
navigationBar.alpha = navigationBar.alpha == 0 ? 1.0 : 0.0;
}];
In this scenario your view will be positioned behind your navbar, even when its alpha is 1.0. The downside to this scenario is that even with a 1.0 alpha you might see a tinge of your view's background color behind the UINavigationBar. Also, all of your subviews will need to be positioned 44 points down from the top.
UIBarStyleDefault or UIBarStyleBlackOpaque Option B is to hide the navbar in a cross-disolve transition animation. This will expose the superview of the UINavigationBar. If you're using a UINavigationController then the black background of the UINavigationController view is what you'll see - but you can set the background color of the UINavigationController view to match your view to get the effect that you want:
UINavigationBar* navigationBar = self.navigationController.navigationBar;
self.navigationController.view.backgroundColor = self.view.backgroundColor;
[UIView transitionWithView: navigationBar
duration: 1.0
options: UIViewAnimationOptionTransitionCrossDissolve
animations: ^{
// toggle:
navigationBar.hidden = !navigationBar.hidden;
}
completion: nil];
One thing to watch out for with this solution might be a layout issue if the UINavigationController updates your view frame because you hid the UINavigationBar. This would be fine except that your subviews might shift up 44 pixels if they're anchored to the top left. To work around this you might consider anchoring your subviews to the bottom of your view instead (either with springs or with layout constraints).
UIBarStyleDefault or UIBarStyleBlackOpaque Option C is to cover up the UINavigationBar with another view, again using a cross-disolve transition animation:
UINavigationBar* navigationBar = self.navigationController.navigationBar;
[UIView transitionWithView: navigationBar
duration: 1.0
options: UIViewAnimationOptionTransitionCrossDissolve | UIViewAnimationOptionAllowAnimatedContent
animations: ^{
// toggle:
const int tag = 1111;
UIView* navOverlayView = [navigationBar viewWithTag: tag];
if ( navOverlayView == nil )
{
navOverlayView = [[UIView alloc] initWithFrame: CGRectInset( navigationBar.bounds, 0, -3 ) ];
navOverlayView.backgroundColor = self.view.backgroundColor;
navOverlayView.tag = tag;
[navigationBar addSubview: navOverlayView];
}
else
{
[navOverlayView removeFromSuperview];
}
}
completion: nil];
UIBarStyleBlackTranslucent: This option is the easiest, as the UINavigationBar is already translucent, and your view is already behind it. Simply animate the alpha:
[UIView animateWithDuration: 1.0
animations: ^{
// toggle:
navigationBar.alpha = navigationBar.alpha == 0 ? 1.0 : 0.0;
}];
You can also try to set a background view underneath the navigation bar and modify this view directly.
private lazy var backgroundView: UIView = UIView()
...
private func setupNavigationBarBackground() {
guard let navigationBar = navigationController?.navigationBar else { return }
navigationBar.setBackgroundImage(UIImage(), for: .default)
navigationBar.isTranslucent = true
view.addSubview(backgroundView)
backgroundView.alpha = 0
backgroundView.backgroundColor = .red
backgroundView.translatesAutoresizingMaskIntoConstraints = false
backgroundView.topAnchor.constraint(equalTo: topLayoutGuide.topAnchor).isActive = true
backgroundView.bottomAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true
backgroundView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
backgroundView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
}
private func changeNavigationBarAlpha(to alpha: CGFloat) {
backgroundView.alpha = alpha
}
This should get you the effect you desire:
self.navigationController.navigationBar.alpha = 0.0;
self.navigationController.navigationBar.frame = CGRectMake(0,0,320,0);
Did not try this in an animation, works in my viewDidAppear though, hope it works.
Swift3
var navAlpha = // Your appropriate calculation
self.navigationController!.navigationBar.backgroundColor = UIColor.red.withAlphaComponent(navAlpha)

Resources