UILabel appearance proxy. setFont deprecated

今日も元気にはま寿C!!

やりたいこと→アプリ全体のフォントを統一したい

どうやら調べてみるとiOS5からはappearance proxyっていうのがあるらしい

http://stackoverflow.com/questions/8707082/set-a-default-font-for-whole-ios-app

ふむふむ

[cpp]
[[UILabel appearance] setFont:[UIFont fontWithName:@"YourFontName" size:17.0]];
[/cpp]

みたいに書けばいいよ~とは書いてあるんだけど、どこに書くの??いや、当然

[cpp]
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
[/cpp]

っしょ、みたいな。。。とりあえず、試してみる(←これ大事)

[cpp]
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.

// URL REF: http://stackoverflow.com/questions/8707082/set-a-default-font-for-whole-ios-app
[[UILabel appearance] setFont:[UIFont fontWithName:@"Meiryo" size:16.0f]];

return YES;
}
[/cpp]

変わらないんけどー。チッ

さらに調べてみるとsetFontはdeprecatedだから~っていうのとappearance proxyを使えるのはUI_APPEARANCE_SELECTORが付けられたメソッドだけだから!っていうことを知る
(UI_APPEARANCE_SELECTORがついているかどうかはUILabel.h等のソースコードまで読め!!って事らしいです。ぷっ)

↑もはや同じ道を辿った人にしか理解できない文章になっている。でもいい、それだけのために存在しているので

なるほどなるほど

http://stackoverflow.com/questions/11308379/uiapperance-not-taking-effect-on-uilabels-created-programatically

だから?もっと具体的な解決法教えて!と思いながらさらにコメントを見ていくと、”こんなメソッド作ってUILabelのカテゴリーで実装すればいいんだよ~”ってのが書いてある。ふむふむ

カテゴリーね。なんかObjective-Cの入門書にチラっと紹介されてたな。Objective-C言語特有の拡張仕様だったな、たしか。なんか雰囲気的にJavascriptのprototypeっぽそう。まぁ、詳しくはObjective-C プログラミング言語(PDF)あたりを読むなりグーグル先生に教えてもらうなりしてくれ

そしていつもハマるのが、このコードの断片。どこに置くんだよ!!そこまで丁寧に教えてくれるとstackoverflow最高~って思えるんだけど。とりあえず、カテゴリーの定義ファイルの命名規則はクラス+カテゴリって感じらしい

[cpp]

@interface UILabel (UISS)
– (void)setTextAttributes:(NSDictionary *)numberTextAttributes UI_APPEARANCE_SELECTOR;
@end

@implementation UILabel (UISS)
– (void)setTextAttributes:(NSDictionary *)numberTextAttributes;
{
UIFont *font = [numberTextAttributes objectForKey:UITextAttributeFont];
if (font) {
self.font = font;
}
UIColor *textColor = [numberTextAttributes objectForKey:UITextAttributeTextColor];
if (textColor) {
self.textColor = textColor;
}
UIColor *textShadowColor = [numberTextAttributes objectForKey:UITextAttributeTextShadowColor];
if (textShadowColor) {
self.shadowColor = textShadowColor;
}
NSValue *shadowOffsetValue = [numberTextAttributes objectForKey:UITextAttributeTextShadowOffset];
if (shadowOffsetValue) {
UIOffset shadowOffset = [shadowOffsetValue UIOffsetValue];
self.shadowOffset = CGSizeMake(shadowOffset.horizontal, shadowOffset.vertical);
}
}
@end

[/cpp]

なのでこれをきっとUILabel+UISS.h、UILabel+UISS.mというファイルに書けばいいのだな

あとはsetFontの変わりに、これを使えば、上手くいくはず、、、、上手く行ってなかったらこのブログの投稿も存在しないだろう、とキレの良いみなさんは既に気づいているはずですね

[cpp]
#import "UILabel+UISS.h"

@implementation AppDelegate

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.

[[UILabel appearance] setTextAttributes:[NSDictionary dictionaryWithObject:[UIFont fontWithName:@"Meiryo" size:16.0f] forKey:UITextAttributeFont]];

return YES;
}
[/cpp]

恐る恐る⌘-Rしてみると、、、変わったー!!!

と、分かりきった結果ではありますが、これで無事アプリ内のUILabelが全てメイリオ(Meiryo)フォントになりました~

UITableView delegate methods

ハマったーいむ とぅーるるるっ

今日の浜ちゃん

UITableViewのUITableViewCellの中のフォントを変えたいんです。ふぉんとにすごく簡単なこと。コードはこんな感じ

[cpp]
– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = @"cell";
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
}

UIFont *myFont = [UIFont fontWithName:@"Meiryo" size:8.0f];
cell.textLabel.font = myFont;

return cell;
}
[/cpp]

しかーし、実行してみるとちっとも小さくなっていない。もしかして、小さくなっているけど私が認識していないだけ?とか思ってフォントサイズを2.0fとか極端に小さくしちゃったりしてね。でも変わらない!!なぜだ。あーイライラする

と思ってコードを見渡すと違う箇所でこんな事してた、自分

[cpp]
– (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = [UIColor whiteColor];
cell.textLabel.font = [UIFont fontWithName:@"Meiryo" size:12.0f];
UIView *bgColorView = [[UIView alloc] init];
[bgColorView setBackgroundColor:[UIColor colorWithRed:41/255.0f green:47/255.0f blue:61/255.0f alpha:1.0f]];
[cell setSelectedBackgroundView:bgColorView];
}
[/cpp]

あー、いつしか昔、何故か忘れたけど、cellの外観を統一するためにwillDisplayCell:をオーバーライドしていたのであった。これはcellが表示される直前に呼び出されるので当然cellForRowAtIndexPath:より後に実行されるのでいくらcellForRowAtIndexPath:の中でフォント変えても意味なかったんだった。ふぉんとバカねぇ、あんた!!

一つのControllerの中のコードが多くなってくると、こういった罠に陥りやすいので注意が必要。特にXcodeを使っていると長いメソッドとか滅多に改修しないコードは折りたたんで非表示にしてしまっているケースもありえるので、さらに注意が必要。私自信は折りたたみ機能は使わないが

これからはもっと#pragma markをうまく使ってソースコードの可読性をよくするように心がけよう

たまにクライミングジムに行くとこういうズボン履いてる人いるよね。登りやすいのかな~?見てるとホールドに引っかかりそうで

UITapGestureRecognizer Not Working

魚ー うおー 浜った!!

iOSでラベル(UILabel)にタップ認識(UITapGestureRecognizer)を追加しようとして

検索するとだいたいラベルのuserInteractionEnabledをYESにしろっていうのが出てくる。そんなの知ってるC。。。素人じゃあるまいし。素人だけど

で、最初に書いてたコードがこれ。1~3までの回答が書かれたラベルエリアがあって、誤った回答をタップするとaddGestureRecognizerした処理が実行されたい、という意図

試してみても動かない

[cpp]
UITapGestureRecognizer *wrongAnswerRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)];
wrongAnswerRecognizer.numberOfTapsRequired = 1;

int correct_answer = [[self.entity valueForKey:@"correct_answer"] integerValue];
if (correct_answer == 1) {
[label2 addGestureRecognizer:wrongAnswerRecognizer];
[label3 addGestureRecognizer:wrongAnswerRecognizer];
} else if (correct_answer == 2) {
[label1 addGestureRecognizer:wrongAnswerRecognizer];
[label3 addGestureRecognizer:wrongAnswerRecognizer];
} else if (correct_answer == 3) {
[label1 addGestureRecognizer:wrongAnswerRecognizer];
[label2 addGestureRecognizer:wrongAnswerRecognizer];
}
[/cpp]

この間にいろんなヘンな事を試すわけです。ラベルの境界線が重なりあって、タップが認識されていないのでは?って疑ってボーダー出してみてラベルの大きさとか位置とか確認したり。もしかしてラベルの下のビュー(superview)のuserInteractionEnableもYESにしないとダメなの?とか。結局イライラして画面連打してたら、3番目の回答をタップしたら処理が実行された!!

デバッグ中の画面の正解回答は2番。ずっとデバッグで1番の不正解ばかり確認してたのでした

そして、修正したコードがこちら

[cpp]
int correct_answer = [[self.entity valueForKey:@"correct_answer"] integerValue];
if (correct_answer == 1) {
[label2 addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)]];
[label3 addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)]];
} else if (correct_answer == 2) {
[label1 addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)]];
[label3 addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)]];
} else if (correct_answer == 3) {
[label1 addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)]];
[label2 addGestureRecognizer:[[UITapGestureRecognizer alloc]
initWithTarget:self action:@selector(wrongAnswer:)]];
}
[/cpp]

同じインスタンスを複数のラベルに指定すると、どうやら後から追加した方にもっていかれるようです。そんなもんで、タップ認識オブジェクト(UITapGestureRecognizer)は必ずView毎にインスタンス化する必要があるようです

知っていれば当然のような事に見えるけど、知らないとハマるかもしれないようなシチュエーション。意外とこういう地味な事に数時間費やしちゃう場合とかある