Set UIKeyboardAppearance across the whole app - ios

Is there a useful property in a cocoa-touch project that would allow setting the one-and-only consistent style of keyboard appearance throughout the app? Say I want UIKeyboardAppearanceAlert on all the textFields and textViews I have in my app without directly modifying anything. Is is possible?

No, it isn't possible. The keyboardAppearance is part of the UITextInputTraits protocol and is not marked as a UIAppearance method. If it was you could do something like:
[[UITextField appearance] setKeyboardAppearance:UIKeyboardAppearanceAlert];
You can identify methods that can be used with the appearance proxy by looking at the docs or, from within your code, at the UIKit headers (command-click on a method and it will take you to the header.
For example, in UINavigationBar.h, you can see this:
#property(nonatomic,retain) UIColor *barTintColor NS_AVAILABLE_IOS(7_0) UI_APPEARANCE_SELECTOR; // default is nil
The marker UI_APPEARANCE_SELECTOR means that this property can be used on the appearance proxy. It isn't present on keyboardAppearance, and it doesn't look like any keys in the info.plist allow you to define an application-wide appearance.
Your best bet is to subclass textfield and textview and use those subclasses everywhere.

Related

How to change default System font for xib?

I've swizzled systemFontOfSize:, boldSystemFontOfSize:, and systemFontOfSize:weight: but when I set the font to "System" in a xib it still sets it to the default value. How can I change the default "System" font for xibs?
I know I swizzled these methods properly because when they are called programmatically it works as expected.
I'm not interested in a solution related to setting label appearance because I need to be able to change the font size.
In my suggest, you can also swizzled initWithCoder: for UILalbel ,UIButton ,UITextField. And modify the font according to your need in the swizzling method.

trouble with UIAppearance and UIButton subclassing

I have a custom button, that is just a standard UIButton, but with a CAGradientLayer added in.
In my custom button, I have defined two properties:
#property (nonatomic, strong) UIColor* topColor UI_APPEARANCE_SELECTOR;
#property (nonatomic, strong) UIColor* bottomColor UI_APPEARANCE_SELECTOR;
If those two values get set, the my button draws itself with a nice linear gradient. Works great.
I also like to put as much into InterfaceBuilder as possible. So, on some of these buttons, in IB's "Identity Inpsector" I add in "User Defined Runtime Attributes" for these properties. Again, works great.
Next, I thought I'd try using UIAppearance proxies. Most of my custom gradient buttons all have the same colors. But there are a few that are different. So, I figured what I would do is use the appearance-proxy stuff to set the default colors for this class, and then for any buttons that are different, I could just set their values in IntefaceBuilder. This fails.
Apparently, what's happening is that it's reading the runtime attributes from my storyboard file first, but afterwards those values get overwritten by the appearance proxy. I wouldn't expect this to work this way, but it does.
Any tips on how to accomplish this? Or should I just give up on the runtime attributes thing?
OK, I've thought about this, and I guess this is really what the Appearance proxy is supposed to do. So, my solution is to have two classes "MySpecialButton" and "MyAppearanceButton".
MyAppearanceButton will be a sub-class of MySpecialButton.
The look of "MyAppearanceButton" will be controlled by the appearance proxy calls. If I want a button that isn't controlled that way, I'll make a "MySpecialButton" and set the properties in the User Defined Runtime Attributes. That should do it.

Subclassing vs Category with Interface Builder

I have read multiple times that we should not subclass a component (a UIButton for example) :
Why shouldn't I subclass a UIButton?
Subclassing a UIButton
The problem is when I use Interface Builder.
For example, I have a button with a precise appearance in a lot of my views. I can set them each time with IB (it's painful), or I can use a custom class to factorize the custom behavior and appearance.
It seems a bit contradictory to me that the only way to simplify the process with IB is to do it the way that everybody recommends against.
Is there a better solution ? Can I use a category with IB ?
Thanks.
You might be able to use the UIView appearance proxy. I don't know what all you're doing to your buttons but this might help:
Put this is your AppDelegate file in the application:didFinishLaunchingWithOptions: method
if([UIButton conformsToProtocol:#protocol(UIAppearanceContainer)]){
[[UIButton appearance] setBackgroundImage:[UIImage imageNamed:#"YourImage"] forState:UIControlStateNormal];
//modify any other UIButton properties you want to set globally
}
The second link you provided was pretty clear, and this is pretty much what apple itself states, subclass, but never mess with the internal structure.
Best example is iOS 7, now things are completely different and, for example, an application I'm maintaining had a subclassed UIControl, and now it has trouble running on the new iOS, simply because, it was built with assumptions on how the internal structure works (iterating the internal subviews replacing some things). You might not get your app rejected, but it will be a pain in the a** to maintain.
As a rule of thumb, anything you can do to an UIButton from the outside, something like this:
[myButton setBackgroundImage:... forState:...];
[myButton setTextColor:... forState:...];
myButton.titleLabel.font = ...
You can move it to the inside of a custom subclass method:
+ (UIButton*)fancyPantsButton
{
UIButton *button = [UIButton butonWithType:UIButtonTypeCustom];
[myButton setBackgroundImage:... forState:...];
[myButton setTextColor:... forState:...];
myButton.titleLabel.font = ...
return button;
}
You can also do this on init or awakeFromNib without problems (and I usually prefer the later).
UIAppearence is also an option, as was suggested by user hw731. Whatever floats your boat, really.
As for the second question, nib files pretty much create instance a class and then fill-in the things it stores using setValue:forKey: when loading (that's why you get an error like "class is not key-value compliant for something" when you screw up a nib), so if something is categorised when the nib is being loaded, then yes, nibs respect categories, as its simply using initWithCoder.. and then filling in the gaps.
And, by the same token, the nib file won't be able to fill-in custom properties, since it doesn't know about them, unless you explicitly add them on the "User Defined Runtime Attributes" in IB (iOS 5 onwards).
Another technique for nibs, is using
#property (strong) IBOutletCollection(UIButton) NSArray *buttons;
And then iterating and customising buttons accordingly (be it via a subclass, category, local method, ...). This method is really helpful if you want just a handful of custom buttons, but not enough to warrant using a subclass.
I don't see any reason that you shouldn't subclass UIButton, especially for your purpose of making configuration with IB easier. Neither of the links you provided explain why you shouldn't subclass, so their assertions don't seem reliable. On the other hand, the presence of UIButtonTypeCustom in UIButton.h gives the impression that the framework authors planned for UIButton subclasses.

Changing value of an object from a different class

I have a ViewController.m with a UIButton and a UIWebView on it.
I've subclassed UIWebView to a class that is now called MyWebView.m.
What is the most efficient way to change the UIButton outlet location value from a method that is inside MyWebView.m
I thought about NSUserDefaults but it feels to me like it's the worst way to go.
Another thought was to copy the next line and also add it inside MyWebView.h:
#property (weak, nonatomic) IBOutlet UIButton *myButton;
and connect it to the button from ViewController.m but I'm also not sure if that's a right thing to do.
What does the button title represent, conceptually? Decide that, and expose it as a string property of your web view and then have your view controller observe the property with key value observing. Or alternatively, extend UIWebViewDelegate with your own protocol, and have the view controller set itself as the web view's delegate. Then have the web view notify its delegate that this value changed.
You can use the app delegate class for persisting the data through the application but this is also not recommended by the good programmers.
One other way is to use Singleton class . This creates only one object per application session so you can use the the value throughout the application also you can modify and access the value. This is the pure approach to go .You can take a look at http://www.galloway.me.uk/tutorials/singleton-classes/

Custom Button created in IB does not allow access to custom methods

I have an iOS app with multiple ViewControllers. Each view has numerous IB generated UIButtons, each set to custom. I need to change the color of the background in normal and highlighted states. Further, I need to vary the colors to an RGB value based on user interaction. Thus, I can't use image files.
I found an example of a custom class derived from UIButton that implements the color change and click methods to change the colors as I desired. I created a test button and changed its IB custom class to my new class.
I have an outlet property for my IB created button.
The problem I am having is in the viewcontroller.m file when I attempt to access the custom method in my class, xcode can't see the methods.
Use IBAction as a return type for that method
Declare that particular method in .h file

Resources