2014年04月11日

iOS7 - スクロールとちょっとだけ Auto Layout (1)

前回 「 テキストフィールドとキーボード管理」では、簡単な入力フィールドとそれに伴うキーボードの使い方を取り上げました。
今回は、UIScrollView 表示コンテンツのスクロールと、iOS7/Xcode5 で格段に使いやすくなたAuto Layout のさわりを、ちょっとだけ、説明します。
両方とも、入力フィールドが画面に多数存在する画面になったときに、キーボードとの調整をにするには欠かせない機能です。

特に Auto Layout は、画面の解像度が多種になる今後を踏まえて、Xcode の Storyboard を使ってコードレスで取り組むのが主流になるでしょう。Auto Layout の詳細は、機会を改めて、ゆっくり説明したいと思っています。

スクロールビュー


UIScrollView の追加



それでは、前回のXcode プロジェクトを開いて、ストーリーボード(Main.storyboard)を選択します。
右下パネルのオブジェクトライブラリから「Scroll View」を選んで、メインビューにドラッグします(図1)
drag_scrollview.png
図1 UIScrollView の配置

縦横のサイズは後で調整しますので、いまは気にしないでください。
スクロールの対象となるコンテンツを格納するビューを、スクロールビュー内にドラッグして入れます。(図2)
前回使ったラベルとテキストフィールドはこのコンテンツビューの中に入れます(後述)。
drag_sc_contents.png
図2 コンテンツビューの配置

スクロールビューとコンテンツビューが、メインビューにぴったり収まるようにサイズを調整します。(図3)
sc_resize_hl.png
図3 スクロールビューのサイズ調整とビュー階層

図3のとおりラベルとテキストフィールドは階層の奥に隠れてしまいいました。
ドキュメントアウトラインの中のこれらのパーツを選択しコンテンツビューのサブビューになるように移動します。(図4)
move_fields_n_labels.png
図4 UIコントロールの移動

移動したら、コンテンツビューの中で、元のレイアウトと同じになるように再配置します。

シミュレータで実行すると、前回の投稿と何ら変わりのない状態で起動するはずです。
スクロールビューにしましたが、表示領域とコンテンツビューのサイズが同じなので、スクロールはできません。

コンテンツビューのサイズ変更


スクロールが可能になるようにコンテンツビューの高さを大きくします。コンテンツビューを選択して、右サイドパネルのサイズ・インスペクターをクリックします。サイズ・インスペクターの「Height」を増やします。(600以上目安)(図5)
resize_content_view.png
図5 コンテンツビューのサイズ調整

スクロールを確認するために「テキスト2」のラベルとテキストフィールドを、コンテンツビューの最下部に移動します。
コンテンツビューをドラッグすると、スクロールビューの表示領域を大きくはみ出しているのが確認できると思います。(図6)
large_content_view2.png
図6 コンテンツビューの高さ

シミュレータで、動作確認しても、まだスクロールの動作をする様子がありません。しかも、Storyboardを4インチで作業していたので、3.5インチのシミュレータでは「テキスト2」のフィールドが隠れてしまって見えません。

これには Auto Layout が関係しています。

Auto Layout


これまで、Auto Layout に関しては、何も意識せずに操作していましたが、Xcode5では、デフォルトでAuto Layout がオンになっています。
右サイドパネルの「File Inspector」を選択して確認してみましょう。Use Auto Layoutにチェックが入っています。(図7)
sb_use_auto_layout.png
図7 Use Auto Layout

Auto Layout の基本は、配置したUIコントロールに対して制約(Constraint)を追加することによって、画面レイアウトを調整します。
この時点で、何も制約を追加していません。何が起こっているかというと、制約が何もないので、ランタイムが自動的に制約を生成して加えているのです。この自動生成は冗長なもので、最適化されたものではありません。
3.5インチのシミュレータで、下のラベルとフィールドが見えなかったのはそのためです。
また、スクロール動作をしない原因は、スクロールビューとコンテンツビューが配置されたままの状態で自動生成され、コンテンツビューの高さは表示領域におさまるように調整されて生成されたようです。

ちなみに、シミュレータの反時計回りまたは時計回りに回転で、Landscape表示してみてください。
コンテンツビューの内容が何も変わらないのがわかると思います。

Auto LayoutのConstraint(制約)を追加


上記の不具合を解決するために、AutoLayoutのConstraint(制約)を追加します。
最初に、スクロールが動作するように制約を加えます。
ScrollViewを選択し、キャンパスの下部ツールバーから、「Pin」をクリックすると、ポップビューが表示されます。(図8)
add_new_constraints.png
図8 制約の追加
表示されたポップビューから上部のアイビームを選択します。図8では上と左の2つが選択された状態ですが、残り2つも選択し、計4つの制約を指定します。数値が「0」を確認して、「Add 4 Constraints」ボタン(図ではまだ2つしか選択いないので「Add 2 Constraints」)をクリックすると。ScrollView に対して4つの制約が追加されます。
図9のように、ドキュメント・アウトラインに4つの制約が追加されたのが確認できます。
add_4constraints_outline.png
図9 4つの制約を追加(ドキュメントアウトライン)
この4つの制約で、スクロールビューが、親であるメインビューの4方向のエッジに対して長さ0でぴったり張り付いた状態を指定しています。回転させてメインビューの大きさが変わってもそれに合わせて変わります。
コンテンツビューを選択して、同様の処理で制約を追加します。今度はスクロールビューを親にした4方向の制約です。(図10)
new_consts_to_content_view.png
図10 コンテンツビューの制約追加

4-inch のシミュレータを実行して、確認します。スクリーンをドラッグしてもスクロールしませんね。
ところが、3.5-inchのシミュレーターにしてみると、スクロールバーが現れて、「テキスト2」のフィールドが見えるようになりました。スクロールしたときのバウンス・エフェクトも確認できます(図11)
sim_scroll.png
図11 3.5-inch シミュレータで動作確認

これはどういうことでしょうか?図12を参照して見てください。下エッジに設定した縦方向スペースの制約をドキュメント・アウトラインで選択して、右パネルのアトリビュート・インスペクターで確認すると、「-82」で固定になっています。
ストーリーボードは4-inchを使用しています。つまり、スクロールビューから見てコンテンツビューのはみ出した分をボトムの制約で固定している状態なので、動けずにいます。
3.5-inch の場合は同じ「-82」でも可動できる部分が残っているのでスクロールできるのです。

fig_scrollable_area.png
図12 コンテンツビューの制約

Auto Layout の命題の一つは、スクリーンのサイズがどんなに変わっても首尾一貫したレイアウトをすることです。これでは、ままならないですね。
ヒントは図12の3.5-inch の部分にあります。
ボトムの制約のConstants の数値を「-82」から「0」にすることで、はみ出した部分を全てスクロール可能にできます。(図13)
change_bottom_edge_constraint.png
図13 ボトムエッジ制約の値を変更

3.5-inch,4-inch両方のシミュレーターで、同じ振る舞いになることろ確認してみてください。

コードを1行も書かずにスクロールする画面を実装できました。
スクロール動作はしているようですが、実は、現時点でこのプロジェクトはまだ問題を含んでいます。
この点に関しては次回「iOS7 - スクロールとちょっとだけ Auto Layout (2)」で説明します。

posted by ayagu at 12:00| Comment(2) | iOS | このブログの読者になる | 更新情報をチェックする

2014年04月10日

iOS7 - テキストフィールドとキーボードの管理

今回から数回にわたって、iOS7 対応のユーザーインターフェースに関連した項目を取り上げてみます。

第1回目として、テキストフィールド(UITextField)と、キーボードの管理についてのチュートリアルです。

早速プロジェクトを作成します。Xcode5を起動して、「Create a new Xcode Project」をクリックし、テンプレートから「Single View Application」を選択します。
その後、「Next」ボタンをクリックすると、「Choose options for your project:」画面が表示されますので、「Product Name」、「Organization Name」、「Company Name」などの項目を入力します。
「Devices」は「iPhone」にします。(図1)

choose_options.png

図1 新規プロジェクトオプション

「Next」ボタンをクリックすると、ファインダーがでますので、プロジェクトを保存するフォルダーを選択して、「Create」ボタンをクリックすると、新規プロジェクトの初期構成が表示されます。

Storyboard へのオブジェクトの配置


左のパネルのプロジェクト・ナビゲーターから「Main.storyboard」を選択し、ストーリーボードを表示し、図2のようにUILabel とTextFieldを2個ずつ配置します。
initial_sb.png
図2 ストーリーボードへ配置

この時点で、シミュレータの種類を選択し、左上の「ビルドと実行」のボタンをクリックしてシミュレータを起動します。(図3)
ios_sim.png
図3 iPhone シミュレーター

図3は「iPhone Retina(3.5-inch)」を起動した画面です。ここで、2つのテキストフィールドのうち、どちらでもかまいません、クリックしてみます。まだプロジェクトにプログラムコードは何も記述していませんが、テキスト入力フィールドは、ファーストレスポンダーになると自動的にキーボードを表示するようになっています。
キーボードが下からスライドアップするのを確認してください。(図4)
sim_keyboard.png
図4 キーボード

いったん表示されると、キー入力は入りますが、その後何をしてもキーボードは閉じません。

キーボードを閉じる


タップしたテキストフィールドはレスポンス・チェーンのファースト・レスポンダーになっています。キーボードを閉じるには、以下のコードのようにテキストフィールドをファースト・レスポンダーから外します。
[myTextField resignFirstResponder];

これを何処に記述するのか。いくつ方法はありますが、今回は、次の2つを紹介します。

  1. 「改行」ボタンを『完了」ボタン(Done)に設定変更して。UITextFieldDelegateメソッドを実装する

  2. ジェスチャー・レコグナイザーを使って、テキストフィールド以外の領域をタップしたら閉じるようにする



UITextFieldDelegateメソッドを実装する


以下のステップで UITextFieldDelegate のtextFieldShouldReturn:textField メソッドを実装します。

  1. IB(Interface Builder)で、2つのテキストフィールドを選択して、右パネルの"Attribute Indicator"を表示します。"Return Key"を"Default"から"Done"に変更します。(図5)
    return_done.png
    図5 リターンキーの変更

  2. ViewController のヘッダーファイル(ViewController.h)へ、次のようにUITextFieldDelegateプロトコルを実装する宣言を加えます。
    @interface ViewController : UIViewController <UITextFieldDelegate>


  3. ViewController オブジェクトをUITextFieldのdelegateに設定する。IB(Interface Builder)で、ストーリーボードのテキストフィールドを選択し、右パネルの "Connections Inspector" を表示、"Outlets" の "delegate"のサークルをViewControllerにドラッグします。(図6)
    text_delegate.png
    図6 Text Field の delegate を設定
    この操作を2つのテキストフィールドに対して行います。

  4. ViewController の実装ファイル(ViewController.m) に以下のデレゲート・メソッドを追加します。
    #pragma mark - UITextFieldDelegate

    - (BOOL)textFieldShouldReturn:(UITextField *)textField
    {
    [textField resignFirstResponder];
    return NO;
    }




ジェスチャー・レコグナイザーを使う


次のステップで2つのテキストフィールドの参照を作って、レコグナイザーを指定します。

  1. IBの"Assistant Editor"を表示します。Xcode5より、アウトレットの参照は実装ファイル(.m)に記述することが可能になりました。これにより他のファイルからプロパティを隠蔽することができるようになりました。
    エディターに実装ファイル(ViewController.m)が表示されているのを確認してください。ヘッダーファイルが表示されていたら実装ファイルに変更してください。(図7)
    assistant_editor.png
    図7 アシスタント・エディター

  2. テキストフィールドから"controlキー+ドラッグ"でViewController.m の"@interface"と"@end"の間にドラッグします。(図8)
    drag_outlet.png
    図8 アウトレットのドラッグ

  3. 表示されたポップビューにプロパティ名を入れます。(図9)
    textfield_prop.png
    図9 プロパティ

  4. 2. 3. を繰り返して、"textField2"という名前でもう一方のテキストフィールドの参照を作成します。結果は以下になります。(図10)
    two_textfields.png
    図10 テキストフィールド・プロパティ

  5. ViewController.mファイルのviewDidLoadメッソッドの下部にコードを、以下のように記述します。
    - (void)viewDidLoad
    {
    . . .

    UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(resign)];
    gestureRecognizer.cancelsTouchesInView = NO;
    [self.view addGestureRecognizer:gestureRecognizer];
    }


    UITapGestureRecognizerを作成して、このViewController のメインビューに追加しています。これは単純に、全てのタップに応答してViewController のresignメソッドを呼び出します。

  6. resignメソッドを実装します。ViewController.mに以下のメソッドを追加します。
    - (void)resign {
    if (self.textField1.isFirstResponder) {
    [self.textField1 resignFirstResponder];
    }
    if (self.textField2.isFirstResponder) {
    [self.textField2 resignFirstResponder];
    }
    }




シミュレータで動作を確認してください。テキストフィールドを以外、または、キーボードの「完了」ボタンをタップすると、キーボードが隠れます。

次回はスクロールとAuto Layout について説明します。
posted by ayagu at 16:13| Comment(0) | iOS | このブログの読者になる | 更新情報をチェックする

2013年09月14日

xcode でマーキング

確実に歳をとっている。やるべきことをすぐ忘れてしまう。
そんな時はテクノロジーに頼ることにする。

ということで、xcode でやるべきことを記録する方法。

ソースコードにコメントとして以下を記録します。

// TODO: あとで実装
// FIXME: 多分バグ、直す
// !!!: 重要
// ???: 意味不明
// MARK: とりあえず


そうすると、エディター上部のブレッドクラム(?)の右端で、適時、確認できます。(図1)
xcode-todo.png
図1 TODO,FIXMEマークの確認



タグ:IOS Xcode
posted by ayagu at 10:07| Comment(0) | iOS | このブログの読者になる | 更新情報をチェックする
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。