testViewクラスのtouchesBeganに
入れてみてコンソールで見張ったわけですよ。コンソールはXcodeの実行>コンソールメニューの方ね。
したらフリックだとこのメソッド自体が呼ばれてませんでした。
で、UIScrollViewのリファレンスを調べると
というプロパティがあって、こいつがデフォルトYESになってて、その場合、一定期間内埋め込みUIViewへのタッチ通知を遅らせておいて、まずはフリックかどうかを判断するみたいっす。
で、そうでない時にはじめて埋め込みUIView側にtouchesBeganを送るようです。
とすると、フリック時もtouchesBeganが呼び出されるようになります。
ただし、UIScrollView側でフリック処理とみなされた時は、結局touchesEndが来ないんでhandleSingleTapは呼び出されません。
で、調子にのってUIScrollViewのtouchesBeganを調べようとしたんですよ。
やり方はUIScrollViewを継承したtestUIScrollViewを作り、scViewControllerクラスのloadViewメソッドでやっている
のUIScrollViewをtestUIScrollViewとするだけです。testUIScrollViewはこんな感じ。
したら、またまた、なんにも来ないわけですわ。
なので、以下のメソッドも加えて実行。
touchesMovedはtouchesBegan、touchesEnded同様printfを追加だけ。hitTestの方はもう少しこってて、UIScrollViewが決定したUIViewのクラスを表示するようにしてます。それが
という部分。NSStringFromClassというAPIでClassを表示用文字列に変換してくれます。基本的にClass名はASCIIのみで構成されるのでエンンコードには無難なUTF8Stringを指定。
もう一つ、その時のUIScrollViewに埋め込まれたUIViewの一覧も表示してます。printviewsていうstatic関数がそれです。
subviewsメソッドで取り出せるのが埋め込まれたUIViewです。埋め込まれたUIView側もUIViewを埋め込めるので、printviewsは再帰呼び出しになってます。再帰呼び出しがわからない人は「再帰呼び出し」でググりましょう。
for…in機能はAppleのドキュメントObjective-C 2.0 プログラミング言語>高速列挙>for…in機能の章を読みましょう。
で、起動直後にフリックしたコンソール出力がこれ
これでわかったのが、まず、testUIScrollViewのhitTestは自分ではなく埋め込まれたtestViewインスタンスを返してるってこと。そりゃそうだわな。全面testViewなわけだし。
hitTestはAppleの日本語ドキュメント「iPhoneアプリケーションプログラミングガイド>イベント処理」の章(この章は結構タッチイベント処理としてキモの部分の話なんで必読です。というか、performSelector: withObject: afterDelay:とcancelPreviousPerformRequestsWithTarget:の手法、まるまる解説されてるじゃん。ファック。)に詳しく説明されてます。
次にわかったのが、タッチイベントを受けたクラスは、イベントを処理しない場合は自分のnextResponderに対し明示的にタッチイベントメソッドを呼び出してやらないと駄目ということ。
この場合ならtestViewのtouchesBegan内で
としてやんないと、testUIScrollViewはtouchesBeganをもらえないってことですな。
self.nextResponderじゃなくsuperを使うのが正当みたいっす。
ちゅーわけで、完全に埋め込みUIView側に主導権が有るので、UIScrollView側でタップ、ダブルタップを実装してもしょうがないとなるわけですな。
ま、どのみちタップ、ダブルタップに対する反応は埋め込みUIView独自のものになるだろうから、埋め込みUIView側で実装するのが正解ではありますな。
ただ、ちょっと気になる事がドキュメントに...
マルチタップやマルチタッチは、それらが最初に発生したサブビューに関連付けられているため、スーパービューではこれらのタッチを受け取ることができません。
????
だってフリック取ってるじゃん。
なんか、気になったんでtestUIScrollViewのtouchesBegan、touchesMoved、touchesEndedをprintfだけの空メソッドにしてみたんすよ。
こんな感じ。
ひぃいい~、それでもフリックやピンチ、ドラッグも機能する~!
どうも、UIScrollViewはタッチイベントとは別のところでフリックやピンチ、ドラッグをおこなってるようですな...
イベントを直接見張ってるっぽい。これもAppleのドキュメントに載ってたよね。まあ、あんまり深入りせずに、ここらへんで切り上げときます。
あと、気づいたんですが2度目以降のタッチでは
というふうにviewのリストにUIImageViewてのが2つできてます。これはスライダー用のビューみたいっす。
今回、ポージングを試してみようかと思ったんだけど、ワーニング、ランタイムエラーで断念。iPhone OS、微妙にOS Xとは違うのか?
なかなか、面白そうな機能なんだけど...
ダイナミックObjective-C:12 ポージングで乗っ取り
というわけで、今回はダラダラとお話だけでした。
printf("testView touchesBegan\n");
入れてみてコンソールで見張ったわけですよ。コンソールはXcodeの実行>コンソールメニューの方ね。
したらフリックだとこのメソッド自体が呼ばれてませんでした。
で、UIScrollViewのリファレンスを調べると
delaysContentTouches
というプロパティがあって、こいつがデフォルトYESになってて、その場合、一定期間内埋め込みUIViewへのタッチ通知を遅らせておいて、まずはフリックかどうかを判断するみたいっす。
で、そうでない時にはじめて埋め込みUIView側にtouchesBeganを送るようです。
scrollview.delaysContentTouches = NO;
とすると、フリック時もtouchesBeganが呼び出されるようになります。
ただし、UIScrollView側でフリック処理とみなされた時は、結局touchesEndが来ないんでhandleSingleTapは呼び出されません。
で、調子にのってUIScrollViewのtouchesBeganを調べようとしたんですよ。
やり方はUIScrollViewを継承したtestUIScrollViewを作り、scViewControllerクラスのloadViewメソッドでやっている
scrollview = [[UIScrollView alloc] initWithFrame:self.view.bounds];
のUIScrollViewをtestUIScrollViewとするだけです。testUIScrollViewはこんな感じ。
@interface testUIScrollView : UIScrollView {
}
@end
@implementation testUIScrollView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
printf("testUIScrollView touchesBegan\n");
[super touchesBegan:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
printf("testUIScrollView touchesEnded\n");
[super touchesEnded:touches withEvent:event];
}
@end
したら、またまた、なんにも来ないわけですわ。
なので、以下のメソッドも加えて実行。
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
touchesMovedはtouchesBegan、touchesEnded同様printfを追加だけ。hitTestの方はもう少しこってて、UIScrollViewが決定したUIViewのクラスを表示するようにしてます。それが
printf(" return view = %s\n", [NSStringFromClass([view class]) UTF8String]);
という部分。NSStringFromClassというAPIでClassを表示用文字列に変換してくれます。基本的にClass名はASCIIのみで構成されるのでエンンコードには無難なUTF8Stringを指定。
もう一つ、その時のUIScrollViewに埋め込まれたUIViewの一覧も表示してます。printviewsていうstatic関数がそれです。
subviewsメソッドで取り出せるのが埋め込まれたUIViewです。埋め込まれたUIView側もUIViewを埋め込めるので、printviewsは再帰呼び出しになってます。再帰呼び出しがわからない人は「再帰呼び出し」でググりましょう。
for…in機能はAppleのドキュメントObjective-C 2.0 プログラミング言語>高速列挙>for…in機能の章を読みましょう。
で、起動直後にフリックしたコンソール出力がこれ
testUIScrollView hitTest
view list up
view = testUIScrollView (0.0,0.0,320.0,460.0)
view = testView (0.0,0.0,500.0,500.0)
return view = testView
testView touchesBegan
testUIScrollView touchesMoved
testUIScrollView touchesMoved
これでわかったのが、まず、testUIScrollViewのhitTestは自分ではなく埋め込まれたtestViewインスタンスを返してるってこと。そりゃそうだわな。全面testViewなわけだし。
hitTestはAppleの日本語ドキュメント「iPhoneアプリケーションプログラミングガイド>イベント処理」の章(この章は結構タッチイベント処理としてキモの部分の話なんで必読です。というか、performSelector: withObject: afterDelay:とcancelPreviousPerformRequestsWithTarget:の手法、まるまる解説されてるじゃん。ファック。)に詳しく説明されてます。
次にわかったのが、タッチイベントを受けたクラスは、イベントを処理しない場合は自分の
この場合ならtestViewのtouchesBegan内で
[self.nextResponder touchesBegan:touches withEvent:event];
としてやんないと、testUIScrollViewはtouchesBeganをもらえないってことですな。
self.nextResponderじゃなくsuperを使うのが正当みたいっす。
ちゅーわけで、完全に埋め込みUIView側に主導権が有るので、UIScrollView側でタップ、ダブルタップを実装してもしょうがないとなるわけですな。
ま、どのみちタップ、ダブルタップに対する反応は埋め込みUIView独自のものになるだろうから、埋め込みUIView側で実装するのが正解ではありますな。
ただ、ちょっと気になる事がドキュメントに...
マルチタップやマルチタッチは、それらが最初に発生したサブビューに関連付けられているため、スーパービューではこれらのタッチを受け取ることができません。
????
だってフリック取ってるじゃん。
なんか、気になったんでtestUIScrollViewのtouchesBegan、touchesMoved、touchesEndedをprintfだけの空メソッドにしてみたんすよ。
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
printf("testUIScrollView touchesBegan\n");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
printf("testUIScrollView touchesEnded\n");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
printf("testUIScrollView touchesMoved\n");
}
こんな感じ。
ひぃいい~、それでもフリックやピンチ、ドラッグも機能する~!
どうも、UIScrollViewはタッチイベントとは別のところでフリックやピンチ、ドラッグをおこなってるようですな...
イベントを直接見張ってるっぽい。これもAppleのドキュメントに載ってたよね。まあ、あんまり深入りせずに、ここらへんで切り上げときます。
あと、気づいたんですが2度目以降のタッチでは
testUIScrollView hitTest
view list up
view = testUIScrollView (0.0,0.0,320.0,460.0)
view = testView (0.0,0.0,500.0,500.0)
view = UIImageView (469.0,72.0,7.0,421.0)
view = UIImageView (257.0,492.0,204.0,7.0)
return view = testView
testView touchesBegan
testView touchesEnded
というふうにviewのリストにUIImageViewてのが2つできてます。これはスライダー用のビューみたいっす。
今回、ポージングを試してみようかと思ったんだけど、ワーニング、ランタイムエラーで断念。iPhone OS、微妙にOS Xとは違うのか?
なかなか、面白そうな機能なんだけど...
ダイナミックObjective-C:12 ポージングで乗っ取り
というわけで、今回はダラダラとお話だけでした。