Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

新しいToDoを追加できるようにする #2

Open
ginrou opened this issue Apr 3, 2015 · 1 comment
Open

新しいToDoを追加できるようにする #2

ginrou opened this issue Apr 3, 2015 · 1 comment

Comments

@ginrou
Copy link
Contributor

ginrou commented Apr 3, 2015

TODOアプリを作ってみようシリーズの第2回目の演習課題です

内容

前回 ( #1 )に引き続き、今度は新しくToDoを入力し追加できるようにします。

todo

目的

  • UITextViewとキーボードについて
  • ViewController間の連携を通してDelegateパターンについて理解する

アプリの仕様

todo-spec-2

前回のアプリをさらに発展させて、ToDoを追加できる画面を追加します。

遷移

ToDo一覧画面上部にナビゲーションバーを配置し、ToDo追加画面へ遷移するボタンを配置します。

ToDo追加画面

追加画面は上部にキャンセルと完了ボタンがあり、それぞれタップすると�以下のように遷移します。

  • キャンセル : ToDo一覧画面に戻る
  • 完了 : ToDo一覧画面に戻り、入力したToDoが追加される

追加画面にはToDo用のUITextViewがありToDoを追加できるようにします。
ToDoは複数行入力できるようにしてください。

実装の方針

Navigation Controllerに追加 19a155c

レギュレーション通りの画面を作るためには右上にボタンを設置する必要があります。iOSアプリでよく目にする、画面上部のバーは”UINavigationBar”です。
UINavigationControllerを用いるとこのUINavigationBarを利用することができます。
そのため、UINavigationControllerでメインのViewControllerを管理するようにstoryboardでViewControllerの構成を変更します。

2015-04-03 7 14 47 pm

また右上に+ボタンを追加します。これは”Bar Button Item” を選択してドロップし、設定を変更します。
最後にボタンタップ時のハンドラを追加して完了です。

新しいViewControllerを追加してToDoを追加できるようにする

新規クラスを追加し表示する 35b3164

先ほどの+ボタンをタップしたら新しく作成したViewControllerを表示させます。

UIViewControllerのサブクラスとして、AddTodoControllerのクラスを新規ファイルから作成します。
次にstoryboard上にViewControllerのオブジェクトを新たに配置し, クラスを”AddTodoController”, Storyboard IDを同じく”AddTodoController”とします。
また、先ほどのボタンタップ時のハンドラでこのAddTodoControllerを生成して表示します。
※この時、キャンセルボタンと完了ボタンを置くためにUINavigationControllerで表示を行います。

AddToDoViewControllerのレギュレーション反映 11820a2

レギュレーションを反映するために、各パーツを配置し、Autolayoutを設定します。

テキスト入力エリアに使うクラスは UITextView です。複数行のテキスト入力や表示の際によく使われるクラスです。
このViewを配置して上下左右をpinで止めるAutolayoutを設定します。

キャンセルボタン、doneボタンはstoryboardからではなくコード上から追加します。

self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel
                                                                                      target:self
                                                                                      action:@selector(cancelButtonTapped:)];

このようにすると、NavigationBarの左上にキャンセルボタンが出現し、タップされるとcancelButtonTappedが呼ばれます。
doneボタンも同様にします。

ここまでの状態でも入力はできるのですが、長い文章を入力するとキーボードの下に潜り込んでしまい、テキストを見ることができなくなってしまいます。
この不具合は次のコミットで直します。

キーボード表示時にTextViewのサイズを変更する d6a319e

�キーボードの下にTextViewが潜り込まないようにするためには”キーボードが表示されたタイミングでTextViewのサイズを変える”ことで対応します。

キーボードが出現したことを検知する

キーボードが出現した時には、UIKeyboardWillShowNotification のキー名でNSNotificationが通知されます。

NSNotification とは

NSNotificationとは、アプリ全体に行き渡る通知を行う仕組みです。[NSNotificationCenter defaultCenter]というシングルトンに対してどのオブジェクトがどのキーに対して通知を受け取るかのobserverを登録します。すると通知が発生したときに登録したメソッドが実行されます。

詳しくはこちらをご覧ください → 7.4 NSNotification、NSNotificationCenter を用いた通知 · mixi-inc/iOSTraining Wiki

この通知を受け取れるようにobserverとして登録します。
(�注意: dealloc時にobserverを解除しないとクラッシュを引き起こします)

通知ごとの詳細は通知されるメソッドの引数であるNSNotificationインスタンスのuserInfoというNSDictionaryのプロパティの中に含まれています。
今回キーボードのサイズが必要なのですが、以下のようにして取得できます。

NSDictionary *userInfo = notification.userInfo;
CGRect keyboardFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];
TextViewのサイズを変更する

Auto layoutを用いてViewの配置を行っている時、Viewのサイズをプログラム上で調整したい場合、そのやり方はいくつかありますが、
簡単な方法の一つは”制約の値を変える”ということになります。
今回のケースだと、TextViewとViewControllerのViewとの間のマージンの制約の値を変更します。
この制約の値は初期値では0(つまりマージンなし)ですが、キーボードが出現したときにキーボードの高さの分だけ制約を大きくすれば良いとなります。

そのためには、以下のステップを経る必要があります。

  • storyboard上の制約をIBOutletプロパティとして追加する
  • キーボード出現時に制約の値を変える

となります。実行結果は以下のようになります。

2015-04-03 8 12 47 pm

わかりやすくするため、TextViewの色を緑にしてあります。

ToDoが追加されたら反映する 091a55d

キャンセルボタン/Doneボタンが押された時に、AddTodoViewControllerを閉じ、追加があればToDoに追加を行います。

ToDoが追加された時、元のViewControllerはどのようにして新しく追加されたToDoを知るためにDelegateパターンを用います。
以下の処理を追加します。

  • プロトコルの宣言とdelegateプロパティの追加
  • キャンセル/Doneボタンタップ時にdelegateメソッドを呼ぶ
  • ViewControllerがプロトコルに準拠し、そのメソッドを実装する

その他情報

教材

スタートブランチ

show-todo

ここまでの完成品

add-todo

@ginrou
Copy link
Contributor Author

ginrou commented Apr 9, 2015

Delegateの宣言は以下のような方法でも可能です。

#import <UIKit/UIKit.h>

@protocol AddTodoViewControllerDelegate <NSObject>
- (void)addTodoViewControllerDoneButtonTapped:(NSString *)todo;
@end

@interface AddTodoViewController : UIViewController
@property (nonatomic, weak) id<AddTodoViewControllerDelegate> delegate;
@end

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant