Styling UILabel using UIAppearance proxy - ios

I have a number of UILabel elements in my app and I'm looking for an easy way to style them using the UIAppearance Proxy object. My current approach is to create different subclasses of UILabel equipped with an UI_APPEARANCE_SELECTOR decorator in order to be accessible though [UILabelSubclass appearance] calls. You can find the sources I'm using as reference here and here.
The problem is that I don't want to set the font size but only the font family relying on the size defined in the Storyboard.
How can I set this in the subclass?

Here's a simple category that works with UIAppearance proxies:
#interface UILabel (FontName)
- (void)setFontName:(NSString *)name UI_APPEARANCE_SELECTOR;
#end
#implementation UILabel (FontName)
- (void)setFontName:(NSString *)name {
self.font = [UIFont fontWithName:name size:self.font.pointSize];
}
#end

I think you can try in your subclass something like:
UIFont *newFont = [UIFont fontWithName:#"YourFontName" size:self.font.pointSize];
self.font = newFont

Thanks to this post, and also a blog post from Peter Steinberger (http://petersteinberger.com/) I was able to get something together that works for me:
#interface UILabel (FontAppearance)
#property (nonatomic, copy) UIFont *appearanceFont UI_APPEARANCE_SELECTOR;
#end
#implementation UILabel (FontAppearance)
- (void)setAppearanceFont:(UIFont*)font
{
[self setFont:font];
}
-(UIFont*)appearanceFont
{
return [self font];
}
#end

Related

About issue related to IBInspectable in localisation

In my app i set localisation text using IBInspectable string and also change language using manually using button action.
Issue
I can't able to refresh UI while change language manually. I need to refresh IBInspectable string while I change language.
I have achieved using below code :
1. InterFace and Implementation for UIView
#interface UIView (AdditionLocalization)
-(void)applyLocalization;
#end
#implementation UIView (AdditionLocalization)
-(void)applyLocalization{
if ([self isKindOfClass:[UILabel class]]) {
UILabel *lbl = (UILabel *)self;
[lbl setLocalizedText:lbl.accessibilityLabel];
}
}
2. InterFace and Implementation for Label
IB_DESIGNABLE
#interface UILabel(LabelAdditionLocalizations)
#property (nonatomic,copy)IBInspectable NSString *localizedText;
#end
#implementation UILabel(LabelAdditionLocalizations)
#dynamic localizedText;
-(void)setLocalizedText:(NSString *)localizedText{
self.text = [UtilityClass get:localizedText.length>0 ? localizedText : self.text alter:#""];
self.accessibilityLabel = localizedText.length>0 ? localizedText : nil;
}
3.Trigger Manually while button click
- (IBAction)clickChangeLanguage:(id)sender {
[UtilityClass setLanguage:current];
for (UIView *view in self.view.subviews) {
[view applyLocalization];
}
}

Will using appearance proxy on UILabel get my app rejected because it alters UIAlertView?

I'm hoping to customize all of the fonts in my app, and have been using the [UILabel appearance] API so far as it seems like the path of least resistance.
I noticed that this also affects the labels inside of the UIAlertView (as expected), but I'm also aware that customizing the alert view may cause an app to get rejected.
Does anyone have any experience with this? Should I just make my own subclass of UILabel instead and apply it manually to each label in my app?
UILabel class conforms to the UIAppearanceContainer protocol, a check of UILabel.h shows that none of its properties are marked with UI_APPEARANCE_SELECTOR, the prerequisite for the use of UIAppearance. So you need to create UILabel subclass as shown below.
#interface SmallLabel : UILabel
#end
#implementation SmallLabel
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
}
return self;
}
#end
I think you can alsotry in your subclass something like:
UIFont *newFont = [UIFont fontWithName:#"YourFontName" size:self.font.pointSize];
self.font = newFont

SetHidden not working

I am trying to show a label for some seconds when i press a button. But the hide function is not working properly.
-(void) hide_label:(NSString *)value{
[value setHidden:YES];
}
Get the error: No Visible #interface for 'NSString' declares the selector 'setHidden:'.
In your example, value is an NSString, not the UILabel. NSString's have no setHidden: method, as the error message suggests.
Instead, you will want to pass in the label itself and then call setHidden:.
So, change the method to:
- (void) hide_label:(UILabel *)label {
[label setHidden:YES];
}
And change all parts of the code that call this method to pass in the UILabel.
NSString is not a subclass of UILabel and does not respond to setHidden: you must call that on the UILabel property itself.
How do you declare your UILabel? It should be something similar to the following if you connect via a nib:
#property (nonatomic, weak) IBOutlet UILabel *label;
or if its created programatically:
#property (nonatomic, strong) UILabel *label;
You can then call setHidden on the label, as it is a property you can use dot syntax:
label.hidden = YES;
You can check its state by using its accessor:
if ([label isHidden]) {
//... do something
}
It might be worth you reading some tutorials on iOS development, Look Here on raywenderlich.com

iOS Storyboard localizable strings do not work on UILabel subclasses

I'm using the new iOS functionnality to translate the storyboards (http://developer.apple.com/library/ios/#referencelibrary/GettingStarted/RoadMapiOS/chapters/InternationalizeYourApp/InternationalizeYourApp/InternationalizeYourApp.html)
The problem with this solution, it does not work with my UILabel subclasses.
Here are the codes for my UILabel subclasses :
.h:
#import <UIKit/UIKit.h>
#interface LabelThinText : UILabel
- (void)awakeFromNib;
-(id)initWithFrame:(CGRect)frame;
#end
.m :
#implementation LabelThinText
- (void)awakeFromNib
{
[super awakeFromNib];
[self setFont:[UIFont fontWithName:#"Raleway-Light" size:[[self font] pointSize]]];
}
-(id)initWithFrame:(CGRect)frame
{
id result = [super initWithFrame:frame];
if (result) {
[self setFont:[UIFont fontWithName:#"Raleway-Light" size:[[self font] pointSize]]];
}
return result;
}
#end
I guess i'm missing something to get the automatic translations from my Storyboard.strings file.
Anyone has an idea ?
Thanks !
I ran into the same problem, and for the same reason, setting a custom font in a label. My strategy was a little more general, though. My custom font is Helvetica-like, so I used Helvetica Neue in IB as a placeholder font. The UILabel subclass translated that to my custom font, preserving font size and weight, so I could control all that through IB.
That made my workaround for the translation bug (I assume it's a bug) easier. I traverse all my views recursively in viewDidLoad, and map all UILabel fonts if they match the placeholder font, and the same for UIButton in my case.
Have you filed a bug?
Encountered the same problem, here's how I got around it:
Drop your custom class, and create a category on UILabel, in your case UILabel+ThinText:
- (void) setThinText:(BOOL)thinText
{
if (thinText) {
[self setFont:[UIFont fontWithName:#"Raleway-Light" size:[[self font] pointSize]]];
}
}
In your storyboard, select your label, choose the Identity Inspector and add the following User Defined Runtime Attribute:
Keypath: thinText – Type: Boolean – Value: checked
I got this issue too. I solve it setting the custom font in each ViewController. Let me show you an example:
CustomViewController.h
#interface CustonViewController
#property (strong, nonatomic) IBOutlet UILabel* someLabel;
#end
The in CustomViewController.m
- (void)viewDidLoad
{
[self setUoFonts];
}
- (void)setUpFonts
{
self.someLabel.font = [UIFont fontWithName:#"AmaticSC-Regular" size:self.someLabel.font.pointSize];
}
And that's it!. You're going to have your translation and your custom font.
Remember to remove the custom class from StoryBoard.

iOS UI Customization optimization

I'm about to begin a big project which will contains a lot of UI customization.
For example, I need an UIView which will look like that :
So I wrote an UIView custom class but i really don't know if my code is optimized and if there are best ways to do that, so could you give me some advice plz ?
Here's my code :
// DPIViewHeader.h
#define HEADER_HEIGHT 30.0f
#define HEADER_COLOR [UIColor colorWithRed:161.0f/255.0f green:209.0f/255.0f blue:249.0f/255.0f alpha:1.0f]
#define BORDER_WIDTH 2.0f
#define BORDER_COLOR [[UIColor colorWithRed:82.0f/255.0f green:159.0f/255.0f blue:210.0f/255.0f alpha:1.0f] CGColor]
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#interface DPIViewWithHeaderTest : UIView
// properties
#property (strong, nonatomic) NSString *title;
#property (strong, nonatomic) UIColor *headerColor;
#property (strong, nonatomic) UIView *headerView;
#property (strong, nonatomic) UIView *contentView;
// methods
- (id)initWithFrame:(CGRect)frame title:(NSString *)title;
- (id)initWithFrame:(CGRect)frame title:(NSString *)title headerColor:(UIColor *)headerColor;
#end
// DPIViewHeader.m
#import "DPIViewWithHeaderTest.h"
#implementation DPIViewWithHeaderTest
- (id)initWithFrame:(CGRect)frame title:(NSString *)title {
self = [super initWithFrame:frame];
if (self) {
self.title = title;
}
return self;
}
- (void)layoutSubviews {
// set header view and content view
self.headerView = [[UIView alloc] initWithFrame:CGRectMake(self.bounds.origin.x, self.bounds.origin.y, self.frame.size.width, HEADER_HEIGHT)];
self.contentView = [[UIView alloc] initWithFrame:CGRectMake(self.bounds.origin.x, self.bounds.origin.y + HEADER_HEIGHT, self.frame.size.width, self.frame.size.height - HEADER_HEIGHT)];
// add title label
UILabel *label = [[UILabel alloc] init];
label.text = self.title;
[label sizeToFit];
label.center = CGPointMake(label.frame.size.width/2 + 10, self.headerView.frame.size.height/2);
label.backgroundColor = [UIColor clearColor];
[self.headerView addSubview:label];
// set color header
self.headerView.backgroundColor = HEADER_COLOR;
// set border attributes
self.layer.borderWidth = BORDER_WIDTH;
self.layer.borderColor = BORDER_COLOR;
self.headerView.layer.borderWidth = BORDER_WIDTH;
self.headerView.layer.borderColor = BORDER_COLOR;
// add subviews
[self addSubview:self.headerView];
[self addSubview:self.contentView];
}
#end
It really depends (like everything :) ) .
Let me tell you why using two scenarios:
The View is non-customisable:
If DPIViewWithHeaderTest is going to be embedded in a UITableViewCell, then well, scroll performance will be terrible due to high memory usage. Therefore improper for this purpose.
The next scenario: just a simple view, somewhere, with a static background, and some data. It's OK than, but not the best solution.
Good Solution
For both purposes I would suggest creating images. A prerendered image is cached and leaves very small memory footprint. Moreover in this case you could even create strechable one. Isn't this great ?
What if a UIView has to be customisable (like colour, size) ? Then this is the only solution but I would consider rewriting the implementation depending on purpose.
If there are going to be lots of such views, they are animated, for example this is a background of UITableViewCell you should consider drawing them using QuartzCore/Core Graphics for better performance.
For just one (or few) view, this implementation is just fine :) .
Last piece of advice
Generally, unless the view is to be customisable, I would suggest creating images.
For three reasons: performance, look and easiness of creation. Believe me, well crafted images look way better than custom drawing :)

Resources