creating color themes in objective-c - objective-c

I am making a simple calculator. However, I want the color theme to change every time the program is loaded (the theme doesn't change while the program is running). I have an array that stores UIColors that I'm using to change the background color, and that works fine. What I want is to also change the colors of the buttons and labels to match the theme. So when a red background is chosen (at random), all the buttons, text and labels have a red color theme. The next time the program is loaded, it has a yellow color theme; and so on and so forth. What would be the best way to do this?

Use the UIAppearance protocol to get an appearance proxy for each class that you want to customize, and call the appropriate methods to make your changes. For example:
[[UINavigationBar appearance] setTintColor:[UIColor redColor]];
[[UIButton appearance] setTintColor:[UIColor redColor]];
See this NSCookbook recipe and read the NSHipster article for more detailed examples.

Related

Animation artifacts when NSImageView intersects NSTextField in an NSPopover

I'm presenting a view in an NSPopover, using code based on this sample code.
The view, and all of its sub-views, are layer-backed. There's a single NSImageView, and several non-editable NSTextFields. The text fields backgroundColors are set to [NSColor textBackgroundColor], and their textColors to [NSColor textColor]. In this way, the text is black if one is using the normal theme, and white if one is using the "dark menu bar and Dock" option (which I'll refer to as "dark theme" from now on). This all works fine, and it looks a little somethin' like this:
Light theme:
Dark theme:
The problem comes when I animate the NSImageView up off the view. As it intersects with the NSTextFields, the image appears to blend with the text fields in an unappealing manner. It happens in both light and dark themes, but it's more icky-looking (it's a technical term) in the dark theme. Dig it:
The code to animate it looks basically like this:
CABasicAnimation* positionAnimation = [CABasicAnimation animationWithKeyPath:#"position"];
positionAnimation.fromValue = [NSValue valueWithPoint:fromPoint];
positionAnimation.toValue = [NSValue valueWithPoint:toPoint];
positionAnimation.duration = imageAnimationDuration;
[self.imageView.layer addAnimation:positionAnimation forKey:#"position"];
self.imageView.layer.position = toPoint;
What have I tried? Oh, what haven't I tried?
First off, my own views don't have any kind of NSVisualEffectView going on. But it seems that NSPopover adds that on its own; you can clearly see my desktop bleeding through the popover in the animation above. That's fine; it's actually a nice effect. But, thinking that my NSImageView was trying to be vibrant, I subclassed NSImageView just to return NO from allowsVibrancy. No change in behavior.
Next, I subclassed NSView to return NO from allowsVibrancy, and made the parent view of my view an instance of that. No change in behavior.
My NSTextFields are set with drawsBackground = NO, so I changed them to YES. No change in behavior. Then, leaving drawsBackground = YES, I set both text field's backgroundColors to [NSColor clearColor]. Here's where it gets weird. This does make the weird drawing go away, but it changes the text color of one of the text fields (the smaller one) to black. Wut? See below.
I gave up on the background colors, and started messing with the text colors. I found that if I set the textColor of the text fields to a discrete color (say, [NSColor blackColor] or [NSColor whiteColor], then the weird drawing problem also goes away. It seems only to get weird when using colors which adapt with the theme such as [NSColor textColor]. That's super lame, because the whole point of using something like [NSColor textColor] is that it adapts to the theme. I could probably hack around and figure out what theme is active and set the colors manually, but I really don't want to go that route if I can help it.
I promise there's a question in here somewhere, and, mercifully, here it is:
How can I fix the animation issue shown above, while still using colors which properly adapt to the current theme?
Sample project on GitHub.
Edit:
The desired result is to have no blending between the image and the text. Something like this:
The image I used in the sample app here maybe isn't the best example to convey the sheer yuckiness of the animation I'm seeing in my actual app. The image in the sample is already mostly white, while in my actual app it's mostly black, and it truly looks horrible when blended with white text.
Visual Effect Views (like used in NSPopover) are totally messed up in OS X Yosemite and they are causing your problem here. It is not your fault, these views are totally buggy.
A workaround on Yosemite should be to set the appearance property of each NSTextField to NSAppearanceNameAqua. Because if the labels don't try to do some weird vibrancy effect, they can't mess things up. The labels still look the same and the strange effect is gone.
My words in code:
self.titleLabel.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
self.descriptionLabel.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua];
Luckily NSVisualEffectView's are working fine now in El Capitan. So your code should work fine there..

UISegmentedControl Buggy Tint Color in IOS 7.1

When setting the tint color of a UISegmentedControl using the Appearance API, the color of the text in each unselected segment takes the color of the UILabel instead only after switching tabs.
A sample program to test this (screenshots below):
Load the program and look at the first tab. Everything is normal, the labels are red and the segments are blue.
Switch away to the second tab, everything is still fine.
Switch back to the first tab, you will see that the segments have changed to be red instead of blue like they should.
App was just loaded, everything is fine:
After switching tabs, color is wrong:
Code responsible (in the app delegate for testing, but happens elsewhere):
[[UILabel appearance] setTextColor:[UIColor redColor]];
[[UISegmentedControl appearance] setTintColor:[UIColor blueColor]];
I have sent this information to Apple in a bug report. They asked for a sample project, but I haven't gotten an answer yet. This only shows up on IOS 7.1. On 7.0, this doesn't happen.
Are there any suggestions or temporary fixes that would resolve this? It makes my app look bad even though I don't think it's my fault (the red is just to test, that would make anybody's app look bad). I have tried setting controls manually by setting the tint of the specific control instead of using the appearance API, but the problem is still there.
As discussed in the comments, use [[UILabel appearanceWhenContainedIn:[UISegmentedControl class], nil] setTextColor:[UIColor blueColor]]; to set the appearance of the internal label contained in a segment control.
Per the Apple documentation: Setting the tintColor property by using the appearance proxy APIs is not supported in iOS 7.
iOS 7 UI Transition Guide
You can also specify text attributes like of UISegmentedControl like font, using setTitleTextAttributes:forState.

weird UITabBar color inconsistency in iOS7

I'm using iOS 7's tintColor and barTintColor properties to color my UITabBar with this code in a subclass of UITabBarController:
[[UITabBar appearance] setBarTintColor:[UIColor colorWithRed:123/255.0 green:47/255.0 blue:85/255.0 alpha:1]];
[[UITabBar appearance] setTintColor:[UIColor colorWithRed:227/255.0 green:180/255.0 blue:204/255.0 alpha:1]];
On three screens, the color is what I want it to be (only two images illustrating this):
One one screen, the color is weirdly lighter. This screen is a UIWebView.
Then on a fourth screen, the color is SUPER-light. This screen is the only one to use a storyboard--the rest are all done programmatically.
What am I doing wrong? Do the fact that the misbehaving screens are a UIWebView and a storyboard have anything to do with why they're misbehaving? And how do I fix them? I've fiddled with the alpha of the bar but it doesn't change anything.
Thanks for your help.
You're seeing tab bar translucency...i.e. the background view is bleeding through and being blurred. If you want to disable this, you can do:
[tabBar setTranslucent:NO]
on your tab-bar.
On your top two images, its not clear to me if the underlying view controller view is edge-to-edge, i.e. your top two images should look like the fourth one since both have pink backgrounds. Anyhow, setTranslucent:NO should make them all look like the top image.
You can also uncheck "Translucent" at the Attributes Inspector:

ios7 toolbar color washed out

In iOS 7, if I set the toolbar background color, it uses a washed out version of the color, not the actual color. At first I thought maybe the toolbar was semi-transparent (not fully opaque) but that doesn't appear to be the problem.
Even using black only give me a light grey color.
[topToolbar setBackgroundColor:[UIColor blackColor]];
I also tried:
[topToolbar setTranslucent:NO];
But that just caused my toolbar color to be ignored completely.
Anybody know how to make it just use the color specified, without any weirdness?
Thanks.
I wasn't aware of the setBarTintColor method previously, but it is what is needed to accomplish this.
[topToolbar setBarTintColor:[UIColor blackColor]];
[topToolbar setTranslucent:NO];

How to make selected icon in tab bar "shiny" despite using [[UITabBar appearance] setSelectionIndicatorImage:SomeCustomImage];

Actually it's shiny by default. However, many of my tab bars do not have shiny icon.
I wonder what did I do wrong that it fails to be shiny?
I look around and I saw that a way to eliminate the shiny glossy image is by doing
[[UITabBar appearance] setSelectionIndicatorImage:SomeCustomImage];
That's what happen. I use custom selector image. Well, what about if I still want that custom selector image and I still want the shiny look?
I look at the code and see no difference.
I set image tint to default and it's still not shiny.
Note: I figured out the problem
The other tab bars use custom selected image
[[UITabBar appearance] setSelectionIndicatorImage:SomeCustomImage];
That removes the gloss.
Well, how do I use setSelectionIndicatorImage and yet maintain shiny glossy look.