dポイントプレゼントキャンペーン実施中!

ObjectiveCを用いてiPhnoneアプリ開発の勉強をしています。

TableViewControllerのセルにUITextFieldを設置し、そのTextFieldをタッチして表示されたキーボードを
キーボードの外がタップされた時に引っ込める(隠す)処理をしたいのですが、うまくできませんでしたので助言をいただきたいです。

Tap Gesture Recognizerを用いる方法や
touchesBeganメソッドを用いてタップを検知し[self.view endEditing:YES];でキーボードを閉じる
という方法を試したのですが、これらたUIViewControllerでないとできないようで、
キーボードの外をタップしても、セルが選択されてしまい、キーボードは閉じませんでした。



この問題に関して、以下のサイトが参考になると思ったのですが、

http://onno.jp/dev/2012/02/uitableview-touchesbe …
>IB で TableView のクラスを TouchableTableView に変更

という部分が、どこを指しているのか分からず、どうしたら良いのか分かりません。
どこのTableViewのクラスを、TouchableTableViewに変更したら良いのでしょうか?

試しにキーボードを引っ込ませる処理を組み込みたいTableViewControllerのスーパークラスを
UITableViewController から TouchabeTableViewに変更してみましたが、うまくいきませんでした・・

タップした時にキーボードが引っ込ませたいTableViewControllerと、
新たに作成したTouchableTableViewはどのようにして関連付けるのでしょうか?

以下にTouchableTableViewのソースコードを書いておきます。
(Xcode6になり、Fileの新規作成画面が変わり、クラスの書き方がいつもと違うようになっているのが気になりますが・・・。)

-----------


■TouchableTableView.h
#import <UIKit/UIKit.h>

@interface UITableView (TouchableTableView)

@end

■TouchableTableView.m
#import "TouchableTableView.h"

@implemention UITableView (TouchableTableView)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesBegan:touches withEvent:event];
[super touchesBegan:touches withEvent:event];
}

@end


---------

回答お願いします

A 回答 (2件)

あなたが作ったTouchableTableView.mは「カテゴリ」が使われていますが、


既存のメソッド(touchesBegan)をカテゴリで上書きするのは大変危険なので
やめた方がよいです。カテゴリを使ってやってよいのは、既存クラスへの
メソッドの追加だけです。メソッドのオーバーライドは基本的に禁止と
考えるべきです。
(参考)
http://kurokawh.blogspot.jp/2010/03/objective-c. …

そもそも、あなたが参考にしたサイトは、カテゴリを使うように書かれていません。
「UITableView のサブクラス TouchableTableView を作成」と書かれており、
カテゴリじゃなくて、UITableViewを継承したサブクラスを作るように書かれています。

もしかして、あなた自身別にカテゴリを使う意図などないのに、
よくわからないまま適当にやって、結果的にカテゴリを使う形に
なってしまっているのではないですか?

>(Xcode6になり、Fileの新規作成画面が変わり、クラスの書き方がいつもと違うようになっているのが気になりますが・・・。)
と書かれていますが、Xcode6になったからといって、別にクラスの書き方は変わっていません。

ただ「New > File」メニューで表示される作成可能なファイル形式の
一覧表示がXcode5と6で若干異なっており、それで混乱しているの
ではないかと思います。

Xcode5で新規クラスファイルを作成するには、通常
「iOS」-「Cocoa Touch」-「Objective-C class」
を選択しますが、
Xcode6でそれに相当するのは
「iOS」-「Source」-「Cocoa Touch Class」
です。
「iOS」-「Source」-「Objective-C File」
というのもありますが、そちらを選ぶと
カテゴリ形式、プロトコル形式、クラス拡張形式のソースのひな型を
作ってしまいますので、誤ってそちらを選んで、意図せずカテゴリを
使ったソースを作ってしまったということはないでしょうか?
もしそうなら作り直した方がよいと思います。

> >IB で TableView のクラスを TouchableTableView に変更
> という部分が、どこを指しているのか分からず、どうしたら良いのか分かりません。
> どこのTableViewのクラスを、TouchableTableViewに変更したら良いのでしょうか?

ちゃんと「UITableView のサブクラス TouchableTableView を作成」できたなら
UITableViewController内のTable ViewのCustom ClassにTouchableTableViewを
指定できるようになるはずです。

それだけでもともとやりたかったことができるかどうかは、私自身検証したことなくて
今は検証する時間もないのでわかりませんが、少なくともそのサイトで書いているのは
カテゴリではなく、通常の継承を使った方法です。
    • good
    • 0
この回答へのお礼

回答ありがとうございます!
お察しの通り、カテゴリを使う意図はありませんでした・・すみません。

クラスファイルの作り方で迷い、カテゴリを選択してみた時に今までのようにヘッダファイルと実行ファイルが作成されたので、クラスの記述方法が変わったんだくらいに思ってました。

ファイルの新規作成方法まで丁寧に教えていただいてとても助かります。

教えていただいた通りにコードを記述し、サブクラスを指定したところ、セルをタップした時でもキーボードを引っ込められるように出来ました!
ただビューを移動するセルをタップすると、キーボードを引っ込めながらビューを移動してしまうので、
NSNotificationとUIKeyboardDidShowNotificationでキーボード表示をBOOL値を管理してキーボードが表示されている時は、キーボード外全体はキーボードを閉じるだけの処理というもともと考えていた動きを実装する事ができました!

あとはスクロール時の処理も組み込んでみたいと思います。

回答ありがとうございました!

お礼日時:2014/10/11 14:10

その「TouchableTableView」というのは、Objective-Cのひとつの概念「カテゴリ」を利用したものです。

カテゴリはほかのオブジェクト指向の言語にはみられない、Objective-C独自のもので、ひじょうに強力で、それゆえ扱いに気をつけたほうがいいものです。カテゴリは、クラスのメソッドを上書きします。既存のFoundation、UIKitフレームワークのクラスも書き換え可能なので、使い方を間違えると、こわいことになりますね。
UIScrollViewは、タッチイベント(touchesBegan:、touchesMoved:、touchesEnded:など)を上位のResponderに渡さない性質を持ちます。UITableViewは、UiScrollViewのサブクラスなので、おなじ性質です。これをカテゴリを使って、タッチイベントを上位のResponderに渡すようにします。
なお、カテゴリは別ファイルとして作成する必要はなく、プログラマの都合のいい場所に記述することができます。今回の例では、UIViewControllerサブクラスの実装ファイル(例:ViewController.m)に記述するといいでしょう。

#import "ViewController.h"

@interface UITableView (Touchable) // カッコ内は、カテゴリ名。任意です。好きな名称をつければいいです。

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

@end

@implementation UITableView (Touchable)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesBegan: touches withEvent: event]; // タッチイベントを、つぎのResponderにそのまま渡す。
}

@end

@implementation ViewController
~中略

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.view endEditing:YES]; // タッチイベントを受け取ったら、キーボードを下げる。
}

~以下略

@end

「super touchesBegan: ~」は、記述しませんでしたが、必要かもしれません。いまのところ私には判断できません。


さて、以上のカテゴリを追加しても、キーボードは下がらないと思います。それは、じつはUITableViewCellもタッチイベントを止めてしまうからなのです。
UITableViewCellのサブクラスを実装していると思います。それにも、

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self.nextResponder touchesBegan: touches withEvent: event]; // タッチイベントを、つぎのResponderにそのまま渡す。
}

を実装してください。そうすれば、テキストフィールド以外のタッチで、キーボードが下がるようになります。

なお、UIScrollViewのプロパティ「keyboardDismissMode」があって、この値を「UIScrollViewKeyboardDismissModeOnDrag」にすると、スクロールビュー(テーブルビュー)をスクロールすることで、キーボードを下げることができます。これはStoryboard上でも設定できるので、「それでもいいか」と思ったら、こちらを使うほうがかんたんです。
    • good
    • 0
この回答へのお礼

回答ありがとうございます!
意図せずカテゴリというものを使っていたようで、カテゴリというものを知りませんでした;すみません。

カテゴリというものについて少し調べてみましたが、既存のクラスにメソッドを追加できるそうですね。
確かに、やりようにやっては何でもできてしまいそうな印象で、それ故に扱いが難しそうです。

今回はカテゴリを使用せずに処理できるようなので使用せずにプログラムを組んでみようと思いますが、今後カテゴリを使う機会があった時、記述方法を参考にさせていただきます!


タップした時だけキーボードを閉じる仕様を考えていましたが、
スクロールした時は閉じないという仕様だと、動作がわずらわしいなと思ったので、
UIScrollViewのプロパティ「keyboardDismissMode」を使ってキーボードを閉じる処理にも挑戦してみようと思います
ありがとうございました

お礼日時:2014/10/11 09:50

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!