Setting adjustsFontSizeToFitWidth globally for all UILabels - ios

We have a multilingual app in which the size of text in labels can change depending on the language in use. e.g. German uses more space than English in a lot of spaces. In such cases, iOS automatically shrinks the text, substituting the middle letters with ".."
e.g. Cancel becomes Ca..el
It's easy to fix these cases individually by setting the adjustsFontSizeToFitWidth to YES in the label. But it's laborious to do so for every single label out there.
Is there a way one could set it to YES globally for all UILabel instances in the app? I tried using UIAppearance but it seems that it does not support the adjustsFontSizeToFitWidth property.

I think you can add the below code at ViewDidLoad for each ViewController of app:
NSArray *allSub = [self.view subviews];
for (id sub in allSub) {
if ([sub isKindOfClass:[UILabel class]]) {
UILabel *lb =sub;
lb.adjustsFontSizeToFitWidth = YES;
}
}

I think more cleaner way is to do a category for UILabel like this:
#import <UIKit/UIKit.h>
#interface UILabel (FR)
#property(nonatomic) UIBaselineAdjustment baselineAdjustment;
#property(nonatomic) CGFloat minimumScaleFactor;
#end
.
#import "UILabel+FR.h"
#implementation UILabel (FR)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (void)didMoveToSuperview {
self.adjustsFontSizeToFitWidth = YES;
self.minimumScaleFactor = 0.5;
[super didMoveToSuperview];
}
#pragma clang diagnostic pop
#end
And include it in your Prefix.h file

Related

Error in if statement while comparing UITextField's text and a string

In my app, I have a view controller which is having a search bar with UItextfield at the top and a UIImageview below that. The image view is initially hidden.
I want this image view to unhide through an if statement. The user will enter keywords into the textfield and when a certain word will match a pre defined string in the.m file, then it must show the image.
I originally had two view controllers but now I added another one (thirdviewcontroller). As I enter a word into the textfield, the simulator will direct me back to the code highlighting in green on this line:
if ([string1 isEqualToString:string2]) {
locationMap.hidden = YES;
This is .h file:
#interface ThirdViewController : UIViewController
{
IBOutlet UITextField *searchLocation;
IBOutlet UIImageView *locationMap;
}
-(IBAction)SearchGo;
#end
This is the .m file:
-(IBAction)SearchGo{
NSString *string1 = searchLocation.text;
NSString *string2= #"sydney";
if ([string1 isEqualToString:string2]) {
locationMap.hidden = YES;
}
}
It sounds like you've accidentally set up a breakpoint. Simply remove the breakpoint by clicking the blue arrow to the left of the line it breaks on.
In viewDidLoad method, use:
locationMap.hidden = YES;
In your -(IBAction)SearchGo method, use:
locationMap.hidden = NO;
OR for your searchGo method:
-(IBAction)SearchGo{
if ([searchLocation.text isEqualToString:#"sydney"]) {
locationMap.hidden = NO;
}else {
//implementation
}
}
I am guessing, you have attached the IBAction with your textfield,searchLocation and triggered the action specifying "Touch up Inside". This will not work for couple of reasons.
First of all, you need to implement the textFieldShouldReturn: delegate method, so that your controller knows when you press return, it should hand over the control from your text field. Then again, a you have attached your action method to your text filed, as soon as you tap on the textfield, it goes to your method and start comparing but at this point, you have typed nothing in your textfield and it fails to conform to your if condition.
the solution is to either use the have a button and attach the action method to that button. That way, after you have typed the word "sydney", and you hit on the button. It will take whatever in your textfield and compare to that.
Here is the solution-
See the extra button named "Go". Attach your method to it.
This is my .h file-
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate>
#property(nonatomic, strong) IBOutlet UITextField *searchLocation;
#property(nonatomic, strong) IBOutlet UIImageView *locationMap;
-(IBAction)SearchGo:(id)sender;
#end
And this is the .m file-
#import "ViewController.h"
#interface ViewController ()
#property(nonatomic, strong) NSString *string1;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark- textfield delegate
- (void)textFieldDidEndEditing:(UITextField *)textField{
self.string1 = textField.text;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
[textField resignFirstResponder];
return YES;
}
-(IBAction)SearchGo:(id)sender{
NSString *string2= #"Sydney";
if ([self.string1 isEqualToString:string2]) {
self.locationMap.hidden = NO;
}
}
#end
Save the string from the textfield after your editing is done through the delegate method. Make sure, you attach the UITextFieldDelegate to your ViewController.
Alternatively, you may want to avoid all this trouble and use the UISearchDisplay controller.

iOS 7 - linkTextAttributes on UITextView works badly

As you can see on UITextView class, linkTextAttributes seems to be a new property available from iOS7:
// Style for links
#property(nonatomic, copy) NSDictionary *linkTextAttributes NS_AVAILABLE_IOS(7_0);
and it should color links differently in an UITextView instance. So I tried to put a static (not editable) UITextView in a view controller (child of a tab bar controller), and set this property like below:
#property (nonatomic,strong) IBOutlet UITextView *copyrightText;
- (void)viewDidLoad
{
[super viewDidLoad];
UIColor *linkColor = [UIColor colorWithRed:202.0f/255.0f green:202.0f/255.0f blue:202.0f/255.0f alpha:1];
NSDictionary *attributes = #{NSForegroundColorAttributeName:linkColor};
self.copyrightText.linkTextAttributes = attributes;
}
but at first load, links color seems to be not set. Then, if I switch to another VC and return to current VC, links color changes. What's the problem with this code?
You can try this line of code. I'm always using this with the animation. I think it can help you achieve that view in first load.
------> [self.view layoutIfNeeded];

Make all instances of UINavigationBar titles lowercase without subclassing?

Some titles in this iOS app are defined in the storyboard. Some of the titles are being set programmatically. Is there a simple way (Obj-C categories maybe?) to make all the titles lowercase without subclassing?
It is possible with a bit of objective-c magic, using method_exchangeImplementations (AKA "Method Swizzling")
#import <objc/runtime.h>
#interface UINavigationItem (New)
#end
#implementation UINavigationItem (New)
- (void)setTitleLower:(NSString *)title {
[self setTitleLower:[title lowercaseString]];
}
+ (void)load {
method_exchangeImplementations(class_getInstanceMethod(self, #selector(setTitle:)), class_getInstanceMethod(self, #selector(setTitleLower:)));
}
#end
Now each call to someNavItem.title = #"Whatever" ([UINavigationItem setTitle:(NSString*)title]) should go through setTitleLower, which in turn also calls the original setTitle with a minor modification, lowercasing the title.
I would avoid having to implement such a category just for the sake of lower-casing all titles for each UINavigationItem. I guess you're experimenting categories.

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.

Property implementation must have declaration in interface

When I try to compile this I get this error. What do I need to add for the property declaration in the interface? If textBox is an instance variable, why does it need to be declared as a property?
ViewController.h
#import <UIKit/UIKit.h>
#interface TNRViewController : UIViewController {
IBOutlet UITextField *textBox;
IBOutlet UILabel *label;
}
- (IBAction)button:(id)sender;
#end
ViewController.m
#import "TNRViewController.h"
#implementation TNRViewController
#synthesize textBox;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)dealloc {
[textBox release];
[label release];
[super dealloc];
}
- (IBAction)button:(id)sender {
NSString *Name = textBox.text;
NSString *Output = Nil;
Output = [[NSString alloc] initWithFormat:#"%# says: Hello World!", Name];
label.text = Output;
[Output release];
}
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {
[textBox resignFirstResponder];
return YES;
}
#end
textBox needs to be declared as a property because you are #synthesizing it in your implementation.
You need to either:
Add the #property declaration for textBox in your interface.
OR, You could remove the #sythesize line from your implementation if you don't plan on needing the setter/getter methods.
by writing #synthesize textBox in your implementation the compiler generates 2 methods for you automatically.
-(UITextField*)textBox
-(void)setTextBox:(UITextField *)textBox
To be accessed these need to be defined in the class' interface. Objective-C for the iPhone has a nifty shortcut for declaring these two methods, the #property directive. You can also include information about how the variable should be stored in this directive.
#property (nonatomic, retain) IBOutlet UITextField * textBox
Would give you your IBOutlet for a text field. It is also a stand in for the 2 methods above. It tells us that the textBox is retained by your class. By always using the setter and getter methods for a variable you can avoid releasing an object and referencing the instance variable later, when it may not be safe. It is best practise to do this. You would access the text field from within your class by doing
[self.textBox setText:#"aString"];
self.textBox.text = #"aString";
(the lines above are equivalent)
This error happened when I added a pod. I ended up deleting a updating my pod file and it fixed the error.

Resources