UITabbarを隠すときに困った(気づいた)事
2ヶ月ぶりくらいの日記です。
長い間書かかなかったのは勿体なかったと思いつつ、適度にまた再開していきます。
前に書くといった記事もちょいちょい書いてきます。
(前も同じ事言った様な)
今回はUITabbarを動的に消すときに困った事についてです。
とりあえずいつも通りぐぐってみるとこの方の下の方に貼ってあるリンクに答えがありました。
http://www.developers-life.com/hide-uitabbarcontrolleruitabbar-with-animation.html
UIViewを継承してるからアニメーション使えるのか。寧ろ使えない方が少ないか。
以下はUIViewアニメーション中のUITabbarを動かしている部分です。
for(UIView *view in tabBarController.view.subviews) { CGRect _rect = view.frame; if([view isKindOfClass:[UITabBar class]]) { if (hiddenTabBar) { _rect.origin.y = 431; [view setFrame:_rect]; } else { _rect.origin.y = 480; [view setFrame:_rect]; } } else { if (hiddenTabBar) { _rect.size.height = 431; [view setFrame:_rect]; } else { _rect.size.height = 480; [view setFrame:_rect]; } } }
tabBarControllerの部分は自分の場合はself.tabBarController.view....になってます。
[UITabbar class]だった場合にorigin.yの位置を変えるのは想像通りだったんですが、elseで書かれているheightをかえる処理、よくわかんないしいらないだろーって思って消去してしまったのが 失敗でしたね。先駆者が書いてくれたソースコードはまずは動かしてみて、そこから検証すべきでした。else以下を消したせいで、白い枠だけが残り、数時間無駄にしました。。
このelseの処理はtabbarController.view内にあるUITransitionViewといわれる物でした。
else if ([view isKindOfClass:[UITransitionView class]])でエラーがでて、予測変換すらされないくせにfor内にてNSLog("view=%@",view);とやると表示されるんです、だからelseで書かれてたのかと納得。リファレンス読んだり、詳しく分かったら追記します。
} else { if (hiddenTabBar) { _rect.size.height = 431; [view setFrame:_rect]; } else { _rect.size.height = 480; [view setFrame:_rect]; } }
そのうちAdBannerとかおく際とかにも出てくる問題らしいのでメモ!
言語ごとに文字を指定出来るNSLocalizedString
iPhoneのアプリ開発において、メニューの文字を英語や日本語ごとに条件分岐で書く必要があると思っていました。Class内で言語ごとに条件分岐して…とやっていたらそんなにobjective-cはお馬鹿じゃなかったです。
さて書こうと思ったんですが、調べてみるとここにすべてが書かれてました。
せめてもの補足としては、
NSString *title = NSLocalizedString(@"SettingTabItemTitle", @"Title of Setting Tab Item");
最初の引数がLocalizable.stringsで書かれている設定名、2つ目の引数がただもメモです。Localizable.stringsの日本語と英語バージョンに
日本語 "SettingTabItemTitle" = @"こっち日本語バージョンへ"
英語 "SettingTabItemTitle" = @"こっち英語バージョンへ"
と記入する事で日本語と英語の場合で識別して表示してくれます。
自分が知らないだけでまだまだ便利な物はありそうですね!
objective-cのプロトコルとデリゲートの違いについて
空気が湿ってきて、天パの自分には嫌な時期ですね。
objective-cがプログラム初めての人にとっては、プロトコルとデリゲートの違いについて悩むかもしれません。なんで、今回は今日1日考えたプロトコルとデリゲートの違いについて自分なりのまとめです。
自分で書いといてなんですが難しい記事を選びましたね。突っ込み募集。
Javaが一番ましに使える言語なんでちょいちょいJavaで置き換えてみます。
プロトコルとは?
プロトコルってIPアドレスのPやら、TCPのPとかしか思いつきませんでした。
objective-cでコードを書いて行く上でデリゲートというものを自然と使っていましたが、知り合いに質問され自分もわからなくプロトコルってデリゲート?な感じになりました。
まずプロトコルとはここの方の資料を大分参考にさせてもらうと
プロトコルはある目的のために必要となるメソッドの宣言ををまとめたもの。 取り入れたメソッドはすべて実装しなければならない。
つまりJavaでいうインターフェースですね。抽象化したメソッドを用意しておいて、それらを実装すれば大丈夫そう。プロトコルの採用は<プロトコル名>ので出来ます。
デリゲートとは?
C#で学んだときは委託すると覚えてました。
例えばコールバック関数と言われているイベント系のものはそうです。
this.btnCallback.Text = "デリゲートによるコールバック"; this.btnCallback.Click += new System.EventHandler(this.btnCallback_Click);
てな感じです。インスタンスを別のインスタンスに受け渡すイメージだと…思ってます。これについてはまだ自分も曖昧かもしれないです。
objective-cのデリゲートも受け渡す、というイメージでプロトコルを定義したクラスで
if([デリゲート名(プロトコル名) respondsToSelector:@selector(プロトコルで定義したメソッド名)]){ [デリゲート名(プロトコル名) selectorで指定したメソッド]; }
を書きます。これにより、プロトコルを<>やったクラス内で定義したメソッドが実装されているのか判定します。そして、もし実装されていれば実行します。
インスタンスとか受け渡してないですが、あるクラスから「デリゲートを<>したクラスに委託している」という感覚でいいと思います。
うーん、一応結論です。
プロトコルとデリゲートの違いについて議論して、なんとなく理解したと思ってたんですが、いざ書いてみるとだめだめですね。
プロトコルはインターフェースと同じで継承したクラスに実装する必要がある。デリゲートはそれにプラスして、そのプロトコルを宣言したクラスから他のクラスに定義したメソッドを見つけ出す事が出来る…ってことでいいのかも。
今後書いてくiPhone記事メモ
ちょっとメモがでたらに今後の予定記事。
Evernoteに書くより公言した方がやると信じてる!
・UI研究【my365編③】 ・NSUserDefaultの使い方 ・NSLocalizedなんたらの使い方 ・シングルトンを使う場合とそうでない場合 ・ストーリーボードを使った作成方法を学ぶ ・UI研究【Path,Cluecoo,NationalParks,ChuChuTune,Pinterestあたり】 ・GitHub便利 ・個人的に作っているアプリの作り方(公開後)
UI研究【my365】のサンプルについてはFacebookAPIとUITableViewを使ったアプリにしてサンプル出します。
ストーリーボードについては興味がある感じです。
もしなんかやってほしい事あったら言ってくれるとネタ増えて嬉しいです。
UIScrollViewに敗北 〜Huluへ逃避〜
久々の日記。毎日続けると言って、復帰してすぐ止まってしまう。そんな時はプログラミングしてるか現実逃避。今回はUIScrollViewと数日間戦って、敗北してHuluに逃げたそんなお話。
UIScrollViewには元々ジェスチャを取得するために元からあるメソッドとして
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
などがあります。これがあれば自分の思い通りなジェスチャーが動作が行なえる…と思っていたのが間違いだった。touchesBeganメソッドとかでオリジナルでやらないと厳しい動作をしようとしてたみたいで…さっさとあきらめてオリジナルでジェスチャ作れば良かった!!
ちなみにHuluでは4400見てます。HEROES好きだったんだけど、俺は4400のほうがちょっと好きかも。宇宙人のようなの出てくるし(ネタバレになるから曖昧に)。2週間無料で今見てるけど、見たいの多くてやめれなさそう。
さ、寝よう。
UIScrollViewでタッチイベントの実装で困った事
UIScrollViewでタッチイベントを取得
UIScrollViewにUIViewをのせて、タッチイベントを取得する際はUIViewにて以下を実装すれば良い
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event - (void)touchesCanceled:(NSSet *)touches withEvent:(UIEvent *)event
これらを実装後、タッチした座標を取得した所、なんと下にスクローした際スクロールのイベントとタッチイベントが重複してしまい座標がとれない。とう自体が起きました。
元々自分は横軸の座標しか使わなかったため、UIScrollViewのスクロールを横の座標を取得している際は止めればおっけーでした。
UIScrollViewはシングルトン化しておいて、(objective-cでシングルトンパターンを試してみた。)
こんな感じに。scroll = [ScrollViewContoller sharedManager];
そして、touchesMoved関数内に
scroll.scrollEnabled = NO;
といれればタッチしたまま動いた際はスクロールしません。
タッチが終わったときはtouchesEnded関数内に
scroll.scrollEnabled = YES;
と入れれば戻ります。
UI研究【my365編②】
Git使い方分かったんでこの関連記事が終わる頃には投稿します。
今回はUI研究【my365編①】の続きです。
前回の考察では
①選択した写真のセルを一番上に移動する。(おそらくアニメーションはYES。後述)その際セルを大きくする。 画像も大きい画像に切り替え。 ②①直後、写真を押すとその写真は徐々に透過する。(微妙) ③②同時、その時のViewの画像を取る。 ④ ③後、アニメーションで③の画像を徐々に下に下げる。 ⑤開く場合は出来上がり?
と書きました。(なんか色がやすっちい)
説明を書いていたら案外多くなりそうなんで考察の①②を細かく説明します。
選択した写真のセルを一番上に移動する
写真を選択する前のフィードはUITableViewで構成されていると思います。
そしてセクションごとに
1セル目:投稿者の画像と名前
2セル目:小さい画像
3、4セル目:いいねボタンとコメント欄
なっていると思います。
1セル目に関してはいいとして、2セル目は元の画像を毎回加工して保存しているのか、加工した画像をダウンロードしているのかわかりません。後者の加工した画像が元々あると仮定しておきます。また3、4セル目に関しては、画像を押すまでは表示されません。
では実際に2セル目の小さい画像を押してセルを一番上にする方法は
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; }
これだけです。セルを選択したときの関数にセルの位置を変更する関数を呼べばOKです。位置を指定する関数についてはぐぐったほうがいいのでてきます。
ここでなぜanimated:YESなのかというと、my365で小さい写真を押して、セルが上に配置される前にもう一度押すと止まるからです。これがanimated:NOだと止まらず上に配置されてしまうからです。
セル数を変更する
説明いるか迷ったんですが、お馬鹿な僕は1ヶ月ごには忘れてしまうため記録のつもりで書きます。
セルを上に配置後、3、4つ目のセルが表示される必要があるためセルの数を指定する関数内にて
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ NSInteger num; NSString *number = [sectionCellNumberManagement_ objectForKey:[NSString stringWithFormat:@"%d",section]]; num = [number intValue]; return num; }
と書きます。
クールな方法が思いつかなかったため、NSMutableDictionary型のsectionCellNumberManagementにセクションごとのセル数を保存しておきます。
セル数の切り替えについては先ほどセルを上に配置した際に利用した、セル選択の関数内で
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ //indexPathからセクションが何番目か取り出し、それをキーに現在のセル数を数える //これはセル数が2の場合(押される前) if([[sectionCellNumberManagement_ objectForKey:[NSString stringWithFormat:@"%d",indexPath.section]] isEqual:@"2"] ) { //コメント数は変動するためsetValueは本当は4ではいけない。 [sectionCellNumberManagement_ setValue:@"4" forKey:[NSString stringWithFormat:@"%d",indexPath.section]]; if(indexPath.row == 0) { NSLog(@"yes 2222"); } else if (indexPath.row == 1) { [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES]; } } else { //略してあります中のifは上記と同じ [sectionCellNumberManagement_ setValue:@"2" forKey:[NSString stringWithFormat:@"%d",indexPath.section]]; } }
セルを大きくする
そして最後に2セル目を高さ340にして出来上がりです。
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ CGFloat cellHeight; if(indexPath.row == 0) { cellHeight = 22; } else if ( indexPath.row == 1) { if ([[sectionCellNumberManagement_ objectForKey:[NSString stringWithFormat:@"%d",indexPath.section]] isEqual:@"2"]) { cellHeight = 75; } else { cellHeight = 340; } } else if ( indexPath.row == 2){ cellHeight = 40; } else { cellHeight = 30; } return cellHeight; }
多分これでそれっぽくなります!
小さい画像と大きい画像の切り替えについては段階をおってついでに書きます。