Nav(22)~Detail Edit(7)

2011. 01. 21
●詳細ビューのキーボードのDoneボタンの変更

現時点ではテキストフィールドの編集は各行に対して個別に行うようになっています。

しかし詳細ビューには4つの編集可能なテキストフィールドがあるので、編集時に出るキーボード右下のDoneボタンをreturnボタンに変更し、returnボタンがタップされると次の行のテキストフィールドに移行するようにします。
(Name: → From: → To: → Party: → Name: とループします)

PresidentDetailController.mを開き、tableView:cellForRowAtIndexPath:でキーボードのDoneボタンと、そのボタンがタップされた時(テキストフィールドの編集が終了した時)に呼び出されるtextFieldDone:メソッドを変更します。

1)tableView:cellForRowAtIndexPath:の変更

tableView:cellForRowAtIndexPath:のセル構成の部分で、テキストフィールドのreturnKeyTypeをDoneボタン(UIReturnKeyDone)に設定していますが、デフォルトのreturnボタン(UIReturnKeyDefault)に戻します。
(太字が修正した部分)

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *PresidentCellIdentifier = @"PresidentCellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PresidentCellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:PresidentCellIdentifier] autorelease];

        UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(10, 10, 75, 25)];
        label.textAlignment = UITextAlignmentRight;
        label.tag = kLabelTag;
        label.font = [UIFont boldSystemFontOfSize:14];
        [cell.contentView addSubview:label];
        [label release];

        UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(90, 12, 200, 25)];
        textField.clearsOnBeginEditing = NO;
        [textField setDelegate:self];
        textField.returnKeyType = UIReturnKeyDefault;
        [textField addTarget:self action:@selector(textFieldDone:) forControlEvents:UIControlEventEditingDidEndOnExit];
        [cell.contentView addSubview:textField];
    }

    // Configure the cell...
    NSUInteger row = [indexPath row];

    UILabel *label = (UILabel *)[cell viewWithTag:kLabelTag];

    UITextField *textField = nil;

    for (UIView *oneView in cell.contentView.subviews) {
        if ([oneView isMemberOfClass:[UITextField class]])
            textField = (UITextField *)oneView;
    }

    label.text = [fieldLabels objectAtIndex:row];

    NSNumber *rowAsNum = [[NSNumber alloc] initWithInt:row];

    switch (row) {
        case kNameRowIndex:
            if ([tempValues objectForKey:rowAsNum])
                textField.text = [tempValues objectForKey:rowAsNum];
            else
                textField.text = president.name;
            break;
        case kFromYearRowIndex:
            if ([tempValues objectForKey:rowAsNum])
                textField.text = [tempValues objectForKey:rowAsNum];
            else
                textField.text = president.fromYear;
            break;
        case kToYearRowIndex:
            if ([tempValues objectForKey:rowAsNum])
                textField.text = [tempValues objectForKey:rowAsNum];
            else
                textField.text = president.toYear;
            break;
        case kPartyIndex:
            if ([tempValues objectForKey:rowAsNum])
                textField.text = [tempValues objectForKey:rowAsNum];
            else
                textField.text = president.party;
            break;
        default:
            break;
    }

    if (textFieldBeingEdited == textField)
        textFieldBeingEdited = nil;

    textField.tag = row;
    [rowAsNum release];
    return cell;
}

1093

本書やサンプルコードではreturnKeyTypeを設定している行を削除していますが、ここではUIReturnKeyDefaultを設定しています。

挙動から言えばNext(UIReturnKeyNext)の方が適切かもしれません。

UIReturnKeyTypeはボタンに表示するテキストを変更するだけで動作には関与しませんので、動作に適切なテキストを自身で決定する必要があります。

2)textFieldDone:の変更

textFieldDone:メソッドはファーストレスポンダを放棄するだけでしたが、次のテキストフィールドに移行するように変更します。
(太字が追加・修正した部分)

- (IBAction)textFieldDone:(id)sender {
    UITableViewCell *cell = (UITableViewCell *)[[sender superview] superview];
    UITableView *table = (UITableView *)[cell superview];
    NSIndexPath *textFieldIndexPath = [table indexPathForCell:cell];
    NSUInteger row = [textFieldIndexPath row];
    row++;

    if (row >= kNumberOfEditableRows)
        row = 0;

    NSUInteger newIndex[] = {0, row};
    NSIndexPath *newPath = [[NSIndexPath alloc] initWithIndexes:newIndex length:2];
    UITableViewCell *nextCell = [self.tableView cellForRowAtIndexPath:newPath];
    UITextField *nextField = nil;

    for (UIView *oneView in nextCell.contentView.subviews) {
        if ([oneView isMemberOfClass:[UITextField class]])
            nextField = (UITextField *)oneView;
    }
    [nextField becomeFirstResponder];
 
}

1094

ここではメソッドを呼び出したテキストフィールドの情報を元にテーブルセルを特定し、行番号をインクリメント(+1加算)して次のセルのインデックスパスを生成し、次のテキストフィールドをファーストレスポンダにする処理を行います。

最初に引数senderからsuperviewプロパティを2回使って、呼び出し元のテーブルセルを特定します。
(テキストフィールド(sender) → コンテントビュー → テーブルセル)

更にテーブルセルのスーパービューであるテーブルビューも取得しておきます。

テーブルビューとセルが特定できたので、そのセルへのインデックスパスtextFieldIndexPathをindexPathForCell:で生成し、rowプロパティで行番号を取得します。

元が最後の行だった場合、次の行として最初の行に戻るようにするため、行番号rowをインクリメントした後にテーブル行数kNumberOfEditableRowsで判定を行い、行数以上の場合は0になるようにします。

newIndex[]は符号無し整数の配列で、0とrow(この時点で移動先の行番号を指す)という2つの要素を持っています。

配列の最初の要素は詳細ビューのテーブルにおけるセクションを指し、今回の場合セクションは1つだけなので0と決め打ちしています。

newIndexを元にinitWithIndexes:length:メソッドで新しいインデックスパスnewPathを生成します。

lengthはノード数、つまりインデックスパスの階層数を指し、配列newIndexの要素数と同じなので2となります。

newPathからcellForRowAtIndexPath:メソッドで移動先のテーブルセルnextCellを取得します。

そして『Nav(20)~Detail Edit(5)』の『12)tableView:cellForRowAtIndexPath:の実装』と同様に、高速列挙でセル内のテキストフィールドを特定します。

最後にbecomeFirstResponderメソッドでファーストレスポンダを移動先のテキストフィールドに設定します。


initWithIndexes:length:

- (id)initWithIndexes:(NSUInteger *)indexes length:(NSUInteger)length

指定した長さのインデックスパスを持つNSIndexPathオブジェクトを生成し、初期化します。

indexes:インデックスパスを作成する、インデックスの配列を指定します。

length:インデックスパスを含めるノード数を指定します。


becomeFirstResponder

- (BOOL)becomeFirstResponder

ウィンドウのファーストレスポンダになることをレシーバに通知します。

戻り値は、レシーバがファーストレスポンダ状態を受理した場合はYES、拒否した場合はNOになります。

デフォルトの実装ではYESを返し、ファーストレスポンダ状態を受理します。

このメソッドはサブクラスでオーバーライドすることができ、選択による強調表示など、状態の更新やいくつかのアクションを行うことができます。

ファーストレスポンダになれるレスポンダオブジェクトは一つのみで、現在のレスポンダがファーストレスポンダ状態を放棄(canResignFirstResponder)すると、新しいレスポンダがファーストレスポンダになることができます。

このメソッドを呼び出すことによって、ファーストレスポンダとなるビューといったレスポンダオブジェクトを作成することができます。

ただしビュー階層内にあるビューからのみ呼び出せます。

ビューのwindowプロパティがビュー階層内にあるUIWindowオブジェクトを保持している場合、ビューは階層から切り離されてnilを返します。


●実行

『ビルドと実行』を行い、詳細ビューでテキストフィールドをタップすると、キーボードの右下のボタンがreturnに変更されています。

1095

returnボタンをタップすると、(キーボードが片付けられずに)次のテキストフィールドにカーソルが移行します。

Party:の次はName:に戻るようになっています。

1096


●サンプルコードとの差異

旧版の本書では、サブビューDetail Editで大統領の名前だけを表示するようになっています。

1092

新版のApress社のサイト内のサンプルコードでは、名前の下にサブタイトルとして任期期間が表示されるようになっています。

1098

セルのサブタイトルの表示は『Simple Table(5)~サンプルコードとの差異』でも行っていますが、復習も兼ねて説明します。

サブビューコントローラのPresidentsViewController.mを開き、セル内容を設定するtableView:cellForRowAtIndexPath:メソッドに修正を加えます。
(太字が追加・修正した部分)

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *PresidentListCellIdentifier = @"PresidentListCellIdentifier";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PresidentListCellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:PresidentListCellIdentifier] autorelease];
    }

    // Configure the cell...
    NSUInteger row = [indexPath row];
    President *thePres = [self.list objectAtIndex:row];
    cell.textLabel.text = thePres.name;
    cell.detailTextLabel.text = [NSString stringWithFormat:@"%@ - %@", thePres.fromYear, thePres.toYear];
    return cell;
}

1097

まずセルの初期化を行っているinitWithStyle:reuseIdentifier:メソッドで、セルのスタイルをデフォルトのUITableViewCellStyleDefaultからサブラベルを表示するUITableViewCellStyleSubtitleに変更します。

このスタイルの変更を行わないと、サブラベルの文字列を設定しても表示されません。

次にセルのdetailTextLabelプロパティで、サブラベル(または詳細ラベル)の文字列をstringWithFormat:メソッドで設定します。

PresidentクラスのインスタンスthePresが既にあるので、任期開始年fromYearと任期終了年toYearをプロパティで呼び出すだけで済みます。



参考文献

NSIndexPath Class Reference

UIResponder Class Reference

はじめてのiPhone3プログラミングはじめてのiPhone3プログラミング
(2009/12/17)
Dave Mark、Jeff LaMarche 他

商品詳細を見る






SoundSport Pulse wireless headphones
0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
04 | 2017/05 | 06
Sun Mon Tue Wed Thu Fri Sat
- 1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31 - - -
Recent Articles
iTunes


Swift
Categories
Tips
Profile

水月杏香

Author:水月杏香
永遠の初心者プログラマ。

Wish List
WACOM


ARC
Technical Q&A
情報プロパティリストキー
Start Developing iOS Apps Today
BOSE

SoundSport Pulse wireless headphones
Reference
NSApplicationDelegateプロトコル
NSArrayクラス
NSAutoreleasePoolクラス
NSBundleクラス
NSBundle UIKit追加分
NSCalendarクラス
NSCoderクラス
NSCodingプロトコル
NSCopyingプロトコル
NSDataクラス
NSDateクラス
NSDateFormatterクラス
NSDictionaryクラス
NSEntityDescriptionクラス
NSEnumeratorクラス
NSErrorクラス
NSExceptionクラス
NSFetchRequestクラス
NSFileHandleクラス
NSFileManagerクラス
NSIndexPathクラス
NSIndexPath UIKit追加分
NSKeyedArchiverクラス
NSKeyedUnarchiverクラス
NSKeyValueCodingプロトコル
NSLocaleクラス
NSManagedObjectクラス
NSManagedObjectContextクラス
NSManagedObjectModelクラス
NSMutableArrayクラス
NSMutableCopyingプロトコル
NSMutableDictionaryクラス
NSMutableSetクラス
NSNotificationクラス
NSNotificationCenterクラス
NSNullクラス
NSNumberクラス
NSObjectクラス
NSObject UIKit追加分
NSObjectプロトコル
NSPersistentStoreクラス
NSPersistentStoreCoordinatorクラス
NSPredicateクラス
NSPropertyListSerializationクラス
NSRunLoopクラス
NSSetクラス
NSStringクラス
NSString UIKit追加分
NSTimerクラス
NSTimeZoneクラス
NSURLクラス
NSURLProtectionSpaceクラス
NSURLRequestクラス
NSUserDefaultsクラス
NSValueクラス

UIActionSheetクラス
UIActionSheetDelegateプロトコル
UIActivityIndicatorViewクラス
UIAlertViewクラス
UIAlertViewDelegateプロトコル
UIApplicationクラス
UIApplicationDelegateプロトコル
UIBarButtonItemクラス
UIBarItemクラス
UIButtonクラス
UIColorクラス
UIControlクラス
UIDatePickerクラス
UIDeviceクラス
UIEventクラス
UIFontクラス
UIGestureRecognizerクラス
UIImageクラス
UIImageViewクラス
UIKit Function
UILabelクラス
UINavigationControllerクラス
UINavigationItemクラス
UIPickerViewクラス
UIPickerViewDataSourceプロトコル
UIPickerViewDelegateプロトコル
UIPinchGestureRecognizerクラス
UIResponderクラス
UIScreenクラス
UIScrollViewクラス
UISearchBarクラス
UISearchBarDelegateプロトコル
UISegmentedControlクラス
UISliderクラス
UISwipeGestureRecognizerクラス
UISwitchクラス
UITableViewクラス
UITableViewCellクラス
UITableViewControllerクラス
UITableViewDataSourceプロトコル
UITableViewDelegateプロトコル
UITapGestureRecognizerクラス
UITextFieldクラス
UITextFieldDelegateプロトコル
UITextInputTraitsプロトコル
UITextViewクラス
UITextViewDelegateプロトコル
UIToolbarクラス
UITouchクラス
UIViewクラス
UIViewControllerクラス
UIWebViewクラス
UIWebViewDelegateプロトコル
UIWindowクラス

AVAudioPlayerクラス
AVAudioPlayerDelegateプロトコル

CADisplayLinkクラス
CAEAGLLayerクラス
CALayerクラス

CGAffineTransform
CGBitmapContext
CGColor
CGColorSpace
CGContext
CGGeometry
CGImage
CGPath

EAGLContextクラス
EAGLDrawableプロトコル

Foundation Constants
Foundation Data Types
Foundation Functions

MPMediaItemクラス
MPMediaItemArtworkクラス
MPMediaPlaylistクラス
MPMediaPropertyPredicateクラス
MPMediaQueryクラス
MPMusicPlayerControllerクラス

Randomization Services

System Sound Services
Amazon


OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
Visitors
QR Code
QR