Custom UILabel creation to avoid localization problems - iphone

Dear programmers,
I am creating a customLabel class like below:
#interface CustomLabel : UILabel {
NSString *customBundlePath;
}
#implementation CustomLabel
- (void)drawTextInRect:(CGRect)rect
{
NSString *result=[self getLocalvalue:self.text];
[result drawInRect:rect withFont:self.font];
}
-(void)awakeFromNib
{
NSLog(#"%#",self.text);
}
-(NSString *)getLocalvalue:(NSString*)textTolocalize
{
// some code
return localizedText;
}
But my problem is, drawTextInRect method calling only once for a Label at the time of nib loading.
If view is Appearing again by popig, then which method will execute for every customLabel object ?
Please help me out.
Thanks, in advance.

You don't need custom classes.
NSString *someTextString = NSLocalizedString(#"SomeText", #"Description of text for translators")
[myLabel setText:someTextString];
Then you can extract the strings from your files and provide proper localization texts.
A couple of useful links:
http://www.icanlocalize.com/site/tutorials/iphone-applications-localization-guide/
http://www.raywenderlich.com/2876/how-to-localize-an-iphone-app-tutorial

Related

Saving an array object as a string within a picker view?

So I am working with a pickerview and need a string to equal one of several things that I have stored in an array. The pickerview code for the components looks like this.
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
switch (row) {
case 0:
image.image = image1;
email = EmailArray[1];
break;
case 1:
image.image = image2;
email = EmailArray[3];
break;
case 2:
image.image = image3;
email = EmailArray[5];
break;
}
NSLog(#"%#", email)
}
This code works just fine as far as I can tell. The NSLog here returns the correct email every time. The user then presses a button that utilizes the "email" string. Here is the first part of that code.
- (IBAction)sendFeedback:(id)sender
{
NSLog(#"%#", email);
}
Only here the NSLog does not return the correct email. It just freezes the program and gives me a threading error that points at that NSLog. Am I not passing the array object to the string correctly?
If I change the code to this it works just fine.
switch (row) {
case 0:
image.image = image1;
email = #"testEmail#gmail.com";
break;
After this both NSLogs will display the test email.
Please help me figure out this problem. If you need more information just ask.
EDIT
Here is the beginning of my ViewController.h file.
#interface ViewController : UIViewController
<UIPickerViewDataSource, UIPickerViewDelegate, UIImagePickerControllerDelegate> {
NSMutableArray *EmailArray;
}
Here is where email is declared in the ViewController.h.
#implementation ViewController
NSString *email;
The error I get looks like this.
Thread 1:EXC_BAD_ACCESS(code=2, address=0x14)
You should not declared email as an instance var. An NSString must be declared as a property with copy modifier
#property (copy, nonatomic) NSString* email;
Your variable is not retained in memory, hence the crash.
You have two options
Add [email retain] after you assign it
Enable ARC and it will retain that variable for you.

Can I reuse colors in Interface Builder?

I've got several yellow buttons created using Inteface Builder. All have the same color. Currently I declare color in each xib. Can I declared it globally and reuse across all xibs?
Not possible in Interface Builder. Do it in code, for example by creating special subclass of the button.
You could use system Color Palette to save the color, but you still need to apply it to all buttons every time you decide to change it. Or you can just use Recently Used Colors in the color chooser, but neither way is enough dynamic.
Yes, you can do this.
At the bottom of the color picker popup in Interface Builder, there's a row of squares you can use to store colors for later use. Drag a color into it from the rectangle where the current color is shown at the top of the color picker to store it, and then just click a stored color later to use it.
I don't believe there is a way to do this entirely in interface builder, unfortunately. However, you can come pretty close with a little bit of code. The best way I've found to be able to change colors throughout the app in one go is to subclass the item that you want to color (UILabel, for instance) to set the color upon initialization:
#interface HuedUILabel : UILabel
#end
#implementation HuedUILabel
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
self.textColor = [AppConfig primaryColor];
}
return self;
}
#end
Then, set the label to have a custom class in IB:
Now, when you want to change the color of all your UILabels, you can do it by changing your one color def AND you don't have to clutter your code with a bunch of appearance assignments.
Most definitely!
Create a singleton object (you can call it OksanaColor, to be cool)...
... or, if you're really lazy, a read-only UIColor property that you can access from your app delegate.
You can also add a category on UIColor, so you can use it same as when you use UIColor. For example in my App I add a new file called ApplicationColors which contains all my app colors.
#interface UIColor (ApplicationColours)
+(UIColor *)savaColor;
#end
Implementation:
#implementation UIColor (ApplicationColours)
+(UIColor *)savaColor
{
return [UIColor colorWithRed:228.0f/255.0f green:86.0f/255.0f blue:86.0f/255.0f alpha:1.0f];
}
#end
Then to use it in my app, I import the ApplicationColours.h and use the same as any other UIColor. i.e:
label.textColor = [UIColor savaColor];
Here's a very simple implementation of a named colors category for UIColor. With this code in your project, UIColor will remember any colors you want to save, and will let you access your own colors or system colors using +colorWithName:
#interface UIColor (namedColors)
+ (UIColor *) colorWithName:(NSString *) name;
+ (void) setColor:(UIColor *) color forName:(NSString *) name;
#end
static NSMutableDictionary *colorStorage;
#implementation UIColor (namedColors)
+ (NSMutableDictionary *) colorStorage
{
if (!colorStorage)
colorStorage = [[NSMutableDictionary alloc] initWithCapacity:10];
return colorStorage;
}
+ (UIColor *) colorWithName:(NSString *) name
{
UIColor *result =[[self colorStorage] valueForKey:name]; // See if we have a color with this name in the colorStorage.
if (result) return result;
SEL selector = NSSelectorFromString(name); // look for a class method whose selector matches the given name, such as "blueColor" or "clearColor".
if ([self respondsToSelector:selector] && (result = [self performSelector:selector]))
if ([result isKindOfClass:[self class]])
return result;
return nil;
}
+ (void) setColor:(UIColor *) color forName:(NSString *) name
{
[[self colorStorage] setValue:color forKey:name];
}
#end

How to setHighlightedTextColor # NSAttributedString

I have a custom UITableViewCell which uses a NSAttributedString. I want it to change color when the cell is selected. How can I make the NSAttributedString have the same behavior as a UILabel with highlightedTextColor set?
I have tried to change the color at the functions setSelected and setHighlighted of the cell, but it seems that they are called to late (on touchUpInside instead of touchDown)
Thanks in advance!
UILabel subclass solution
#implementation CustomLabelHighlighted
{
NSAttributedString *savedAttributedString;
}
-(void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
if (!highlighted)
{
[super setAttributedText:savedAttributedString];
return;
}
NSMutableAttributedString *highAttributedString = [savedAttributedString mutableCopy];
NSRange range = NSMakeRange(0, highAttributedString.string.length);
[highAttributedString addAttribute:NSForegroundColorAttributeName value:self.highlightedTextColor range:range];
[super setAttributedText:highAttributedString];
}
- (void)setAttributedText:(NSAttributedString *)attributedText
{
[super setAttributedText:attributedText];
savedAttributedString = attributedText;
}
#end
Typically it's pretty simple to detect selection/highlighting and change colors depending on it. The important methods are:
-(void)setHighlighted:animated:
-(void)setSelected:animated:
note that when overriding you have to use the methods with animated:, otherwise it won't work.
When you want to change only the color, the simplest solution is to let the color to be set on the label and not on the string. Note that the attributed string is still inheriting all the properties of the UILabel.

How do I set a custom font for the whole application?

Is there any way to How to Apply global font [new custom font] to whole application in iphone objective-c.
I know that we can use below method to set font for each label
[self.titleLabel setFont:[UIFont fontWithName:#"FONOT_NAME" size:FONT_SIZE]];
But I want to change for whole application.
Please help me if anyone know.
Apparently to change ALL UILabels altogether you will need to setup a category on UILabel and change the default font. So here's a solution for you:
Create a file CustomFontLabel.h
#interface UILabel(changeFont)
- (void)awakeFromNib;
-(id)initWithFrame:(CGRect)frame;
#end
Create a file CustomFontLabel.m
#implementation UILabel(changeFont)
- (void)awakeFromNib
{
[super awakeFromNib];
[self setFont:[UIFont fontWithName:#"Zapfino" size:12.0]];
}
-(id)initWithFrame:(CGRect)frame
{
id result = [super initWithFrame:frame];
if (result) {
[self setFont:[UIFont fontWithName:#"Zapfino" size:12.0]];
}
return result;
}
#end
Now ... in any view controller you want these custom font labels, just include at the top:
#import "CustomFontLabel.h"
That's all - good luck
Ican's solution with category might be prefered just to save the day. But avoid using category to override existing methods as apple explains:
Avoid Category Method Name Clashes
... If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. ...
Note also that overriding -(id) init; would be safer than overriding -(id)initWithFrame:(CGRect)frame. You would not face with the problem of not receiving touch events when clicking on a label on UIButtons.
Is this what you mean?
#interface GlobalMethods
+(UIFont *)appFont;
#end
#implementation GlobalMethods
+(UIFont *)appFont{
return [UIFont fontWithName:#"someFontName" size:someFontSize];
}
#end
...
[self.titleLabel setFont:[GlobalMethods appFont]];
In case you want to do it somehow automatically (without using setFont on each control), I don't believe it's possible.
If you can limit your application – or this particular feature – to iOS 5, there’s a new API coming that lets you skin the default UI very conveniently. I can’t give you details, since they are still under NDA at the time I am writing this. Take a look at iOS 5 beta SDK to find out more.
CustomLabel.h
#import <UIKit/UIKit.h>
#interface VVLabel : UILabel
#end
CustomLabel.m
#import "CustomLabel.h"
#define FontDefaultName #"YourFontName"
#implementation VVLabel
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder: aDecoder];
if (self) {
// Initialization code
// Static font size
self.font = [UIFont fontWithName:FontDefaultName size:17];
// If you want dynamic font size (Get font size from storyboard / From XIB then put below line)
self.font = [UIFont fontWithName:FontDefaultName size:self.font.pointSize];
}
return self;
}

Setting a delegate using blocks in iPhone

On a view controller I have multiple textfields, which all use the same delegate. Now in the delegate the code gets really ugly since I have to differentiate between all the textfields (bunch of if/else-if or a switch statement). I came a cross this article:
Blocks in textfield delegates
But from this I still don't understand how this solves the problem? Doesn't this basically call one method and pass it the text and the method has no idea what textfield gave the string? You would still need to differentiate between the textfields, but this time inside the block (with the usual if(textfield == bazTextField)...).
I don't know that it exactly solves the problem so much as shifts it (and into viewDidLoad, which usually gets a bit of mush-mash in it anyway).
However in that example the block itself was being passed in the textfield to run comparisons with and "remembers" the values of all the instance variables as well (if it refers to them), so that's how it knows what text and text field is being dealt with.
I don't see how that code exactly is supposed to help though, since it assigns one block to the single delegate class to be used with all text field delegates - unless perhaps you were supposed to have one per text field, each with a different block. Then you have way more code than you'd have had with the if statements!
The article doesn't make it clear, but I believe the idea is to create one of these blocks (and block delegate objects) for each UITextField that you wish to have respond to textFieldShouldReturn.
hm, maybe I didn't completely understand the article, but I don't see the advantage of using blocks instead of selectors in that concrete example.
you could achieve something similar like this
#interface AlternativeTextFieldDelegate : NSObject <UITextFieldDelegate>
{
SEL selectorToCall;
id objectToCall;
}
- (void) setObjectToCall:(id)obj selector:(SEL)selector;
#end
#implementation AlternativeTextFieldDelegate
- (void) setObjectToCall:(id)obj selector:(SEL)selector
{
objectToCall = obj;
selectorToCall = selector;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[objectToCall performSelector:selectorToCall];
return YES;
}
#end
and the view controller
#interface ViewWithTextFieldsController : UIViewController
{
UITextField *tf1;
AlternativeTextFieldDelegate *delegateForTF1;
UITextField *tf2;
AlternativeTextFieldDelegate *delegateForTF2;
}
// ...IBOutlets and all that...
- (void) tf1ShouldReturn; // handles shouldReturn for tf1
- (void) tf2ShouldReturn; // handles shouldReturn for tf2
#end
#implementation ViewWithTextFieldsController
- (void) viewDidLoad // or wherever
{
delegateForTF1 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF1 setObjectToCall:self selector:#selector(tf1ShouldReturn)];
tf1.delegate = delegateForTF1;
delegateForTF2 = [[AlternativeTextFieldDelegate alloc] init];
[delegateForTF2 setObjectToCall:self selector:#selector(tf2ShouldReturn)];
tf2.delegate = delegateForTF2;
}
// ...
#end
don't really know if that's any better than chaining if-elses though.
it seems to me that this complicates things more than the problem it solves.