FC2ブログ

QuartzFun(6)~タッチイベントの編集

2011. 08. 28
iOS Viewプログラミングガイド』の『カスタムビューの定義』において、『タッチを自分で処理する場合は、touchesBegan:withEvent:、touchesMoved:withEvent:、 touchesEnded:withEvent:、およびtouchesCancelled:withEvent:メソッドをオーバー ライドします(他にどのタッチ関連のメソッドをオーバーライドするかにかかわらず、 touchesCancelled:withEvent:メソッドは常にオーバーライドが必要であることに注意し てください)。』とありますが、本書ではtouchesCancelled:withEvent:メソッドに触れておらず、(サンプルコードも含めて)実装もされていません。

今回はQuartzによるビューのカスタム描画が目的なので実装していませんが、ご自身でアプリケーションを作る際には注意してください。


7)touchesBegan:withEvent:メソッドの実装

touchesBegan:withEvent:メソッドはビューがタッチされた際の処理を記述するメソッドで、ここではランダム色の設定と、タッチされた座標を検出しドラッグの始点と終点として設定、再描画領域の設定と再描画の要請を行います。

最初にナビゲーションバーのセグメンテッドコントロールでランダム色が選択されているかを判別し、ランダム色の場合はUIColorのカテゴリメソッドのrandomColorを呼び出し、currentColorに設定します。
(これによりタッチする度に色が変わることになります)

次にタッチ情報のセットtouchesからanyObjectメソッドでオブジェクトを取り出し、UITouchのインスタンスとします。

そしてlocationInView:メソッドでタッチ位置を取得し、始点firstTouchと(ドラッグしなかった場合のため)終点lastTouchに設定します。

続いて再描画領域redrawRectの初期化を行います。

画像を貼り付けるImageが選択されていた場合は、タッチ位置を中心として画像を貼り付ける都合上、再描画領域の原点をオフセットで補正し、更に画像全体の領域を再描画領域として初期化します。

画像以外の場合は単純にタッチ位置を原点とし、領域は(0, 0)としています。

最後にsetNeedsDisplayメソッドでビュー全体を再描画(つまり既存の図形や画像を消去)します。


touchesBegan:withEvent:

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

ビューまたはウィンドウ内に、指を一本以上タッチした時にレシーバに伝えます。

このメソッドはデフォルトでは何も実装しません。

しかしUIResponderはUIKitの直接のサブクラスであり、特にUIViewのレスポンダチェーンにメッセージを転送します。

次のレスポンダにメッセージを転送するには、以下のようにsuper(スーパークラスの実装)にメッセージを送信し、次のレスポンダに直接メッセージを送信しないでください。

[super touchesBegan:touches withEvent:event];

このメソッドを(一般的な使用パターンである)superの呼び出しをせずにオーバーライドする場合は、タッチイベント処理のため他のメソッドをスタブとして実装し、オーバーライドする必要があります。

マルチタッチはデフォルトでは無効になっています。

マルチタッチイベントを受け取れるようにするには、同じビューインスタンスのmultipleTouchEnabledプロパティをYESに設定する必要があります。

touches:eventによって表された、イベントの開始フェイズのためのタッチ操作を表す、UITouchインスタンスのセットを指定します。

event:タッチ操作が属するイベントを表すオブジェクトを指定します。


locationInView:

- (CGPoint)locationInView:(UIView *)view

指定したビューの座標系内におけるレシーバの現在位置を返します。

戻り値は、view内のレシーバの位置を示す点です。

このメソッドは、指定したビューの座標系内のUITouchオブジェクトの現在位置を返します。

タッチオブジェクトは他のビューから当該ビューへ転送されている可能性があるので、このメソッドはタッチされた位置を指定したビューの座標系へ必要な変換を実行します。

view:タッチ位置を必要とする座標系のビューオブジェクトを指定します。
カスタムビューで自身の座標系でタッチされた位置を取得してタッチの処理をする場合は、selfを指定することができます。
ウィンドウの座標系内でのタッチ位置を取得する場合はnilを渡します。


setNeedsDisplay

- (void)setNeedsDisplay

再描画が必要であるとして、レシーバの境界矩形全体をマークします。

ビューのコンテンツを再描画する必要がある場合に、システムに通知するためにこのメソッドまたはsetNeedsDisplayInRect:を使用することができます。

このメソッドは要求の印をマークすると、すぐにコードに制御を戻します。

ビューは次の再描画サイクルまでは実際に再描画されず、全て無効化された時点でビューが更新されます。

:ビューがCAEAGLLayerオブジェクトによって背景になっている場合、このメソッドは効果がありません。
これは(UIKitやCore Graphicsなど)ネイティブの描画技術を使用してコンテンツを描画したビューのみを意図しています。

ビューのコンテンツや外観を変更した時のみ、ビューの再描画を要求するためにこのメソッドを使用する必要があります。

単にビューのジオメトリを変更する場合は、通常ビューを再描画しません。

代わりにビューのcontentModeプロパティの値に基づいて、既存のコンテンツが調整されます。

再描画する必要の無いコンテンツの変更を避けることによって、既存のコンテンツの再表示のパフォーマンスを向上させることができます。


8)touchesEnded:withEvent:メソッドの実装

touchesEnded:withEvent:メソッドは、ビューからタッチされた指が離れた際の処理を記述するメソッドで、ここでは指が離れた座標を検出しドラッグの終点として設定し、再描画領域の拡張と再描画の要請を行います。

最初に前述のtouchesBegan:withEvent:と同様に、タッチ情報のセットtouchesからlocationInView:メソッドで指が離れた位置を取得し、ドラッグの終点lastTouchとして設定します。

次に再描画領域redrawRectの拡張を行います。

CGRectUnion関数を使用して、touchesBegan:withEvent:で初期化したredrawRectに終点lastTouchによって変わる領域を加えます。

画像を貼り付けるImageが選択されていた場合は、終点を中心とした画像全体の領域を加えます。

それ以外の場合は、ドラッグした始点と終点によって決定される矩形が加えられます。

その後、CGRectInset関数で再描画領域を線幅(drawRect:メソッド内でCGContextSetLineWidth関数で指定した値)の分を、x、yそれぞれの方向に2ポイントずつ拡大しています。

最後にsetNeedsDisplayInRect:メソッドで再描画領域の描画を要請します。


touchesEnded:withEvent:

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

ビューまたはウィンドウから、指を一本以上離した時にレシーバに伝えます。

このメソッドはデフォルトでは何も実装しません。

しかしUIResponderはUIKitの直接のサブクラスであり、特にUIViewのレスポンダチェーンにメッセージを転送します。

次のレスポンダにメッセージを転送するには、以下のようにsuper(スーパークラスの実装)にメッセージを送信し、次のレスポンダに直接メッセージを送信しないでください。

[super touchesEnded:touches withEvent:event];

オブジェクトがtouchesEnded:withEvent:メッセージを受信した時、touchesBegan:withEvent:の実装内に確立した状態情報をクリーンアップする必要があります。

マルチタッチはデフォルトでは無効です。

マルチタッチイベントを受け取れるようにするには、同じビューインスタンスのmultipleTouchEnabledプロパティをYESに設定する必要があります。

このメソッドを(一般的な使用パターンである)superの呼び出しをせずにオーバーライドする場合は、タッチイベント処理のため他のメソッドをスタブとして実装し、オーバーライドする必要があります。

touches:eventによって表された、イベントの終了フェイズのためのタッチ操作を表す、UITouchインスタンスのセットを指定します。

event:タッチ操作が属するイベントを表すオブジェクトを指定します。


CGRectUnion

CGRect CGRectUnion (
    CGRect r1,
    CGRect r2
);

2つの元となる矩形を含む最小の矩形を返します。

両矩形は和集合の計算をするために、事前に標準化してください。

矩形のどちらかがnull矩形の場合、もう一方の矩形のコピーが返されます(両矩形がnullの場合は、結果にnull矩形が入ります)。

それ以外の場合は、完全に元の矩形を含んだ矩形が返されます。

r1:一つ目の元となる矩形を指定します。

r2:二つ目の元となる矩形を指定します。


CGRectInset

CGRect CGRectInset (
    CGRect rect,
    CGFloat dx,
    CGFloat dy
);

同じ中心点を持つ、元の矩形より小さいまたは大きい矩形を返します。

戻り値は、原点の値はx軸はdx引数によって指定された距離、y軸はdy引数によって指定された距離がオフセットされ、サイズが(2*dx, 2*dy)に調整された、元の矩形に比例した矩形になります。

dxとdyが正の値の場合は矩形のサイズが縮小します。

dxとdyが負の値の場合は矩形のサイズが拡大します。

矩形は標準化されてから挿入される引数が適用されます。

結果として得られる矩形が、負の高さまたは幅の場合は空の矩形が返されます

rect:元となるCGRect構造体を指定します。

dx:元の矩形の調整に使用するx座標値を指定します。
挿入する矩形を生成するには、正の値を指定します。
大きく囲む矩形を生成するには、負の値を指定します。

dy:元の矩形の調整に使用するy座標値を指定します。
挿入する矩形を生成するには、正の値を指定します。
大きく囲む矩形を生成するには、負の値を指定します。


setNeedsDisplayInRect:

- (void)setNeedsDisplayInRect:(CGRect)invalidRect

再描画が必要であるとして、レシーバの指定された矩形をマークします。

ビューのコンテンツを再描画する必要がある場合に、システムに通知するためにこのメソッドまたはsetNeedsDisplayを使用することができます。

このメソッドは、無効な矩形を示すビューの現在のリストに指定された矩形を追加すると、すぐにコードに制御を戻します。

ビューは次の再描画サイクルまでは実際に再描画されず、全て無効化された時点でビューが更新されます。

:ビューがCAEAGLLayerオブジェクトによって背景になっている場合、このメソッドは効果がありません。
これは(UIKitやCore Graphicsなど)ネイティブの描画技術を使用してコンテンツを描画したビューのみを意図しています。

ビューのコンテンツや外観を変更した時のみ、ビューの再描画を要求するためにこのメソッドを使用する必要があります。

単にビューのジオメトリを変更する場合は、通常ビューを再描画しません。

代わりにビューのcontentModeプロパティの値に基づいて、既存のコンテンツが調整されます。

再描画する必要の無いコンテンツの変更を避けることによって、既存のコンテンツの再表示のパフォーマンスを向上させることができます。


9)touchesMoved:withEvent:メソッドの実装

touchesMoved:withEvent:メソッドは、ビュー上でタッチしている指が移動している際の処理を記述するメソッドで、ここでは移動中の指の座標を検出して仮の終点として設定し、再描画領域の拡張と再描画の要請を行います。

前述のtouchesEnded:withEvent:と同様に、ドラッグ中の座標を仮の終点lastTouchとして設定し、再描画領域redrawRectの拡張を行います。

画像を貼り付けるImageが選択されていた場合に画像全体の領域をredrawRectとする部分は変わりませんが、touchesEnded:withEvent:の場合と異なり、(else文に書かれていないので)それ以外の場合と区別無くCGRectUnion関数でcurrentRectと合成されています。

後程サンプルコードの差異でも触れますが、ここでtouchesEnded:withEvent:での処理と異なる処理を行う必然性は特になく、移動中だからといって画像を選択した場合にもcurrentRectとの合成を行う必要はありません。
(else文でCGRectUnionによる合成を行っても見た目の動作は変わりません)

むしろtouchesEnded:withEvent:に記述されていた、CGRectInset関数による線幅の補正が削られていることにより、Image以外の図形の描画の際は移動中の図形が線幅分小さく描画され、指を離した時に線幅分大きくなる症状が出ます。
(Lineも影響は見え難いですが、線分の端が影響されています)

これは補正文をコピー&ペーストすることで解決します。


touchesMoved:withEvent:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

ビューまたはウィンドウ内で、一本以上の指に関連付けされたイベントが移動した時にレシーバに伝えます。

このメソッドはデフォルトでは何も実装しません。

しかしUIResponderはUIKitの直接のサブクラスであり、特にUIViewのレスポンダチェーンにメッセージを転送します。

次のレスポンダにメッセージを転送するには、以下のようにsuper(スーパークラスの実装)にメッセージを送信し、次のレスポンダに直接メッセージを送信しないでください。

[super touchesMoved:touches withEvent:event];

マルチタッチはデフォルトでは無効です。

マルチタッチイベントを受け取れるようにするには、同じビューインスタンスのmultipleTouchEnabledプロパティをYESに設定する必要があります。

このメソッドを(一般的な使用パターンである)superの呼び出しをせずにオーバーライドする場合は、タッチイベント処理のため他のメソッドをスタブとして実装し、オーバーライドする必要があります。

touches:eventによって表された、イベント中の移動タッチ操作を表す、UITouchインスタンスのセットを指定します。

event:タッチ操作が属するイベントを表すオブジェクトを指定します。


10)deallocメソッドの編集

deallocメソッドでは、Objective-Cのオブジェクトの2つのプロパティcurrentColorとdrawImageの解放を行っています。


●実行

touchesMoved:withEvent:メソッドのところで述べたように、ドラッグ中と後では図形表示にズレが生じます。

ドラッグ中)
7513

ドラッグ後)
7514

静止画で比較すると分かり難いですが、実際にシミュレータなどで操作するとすぐ気付きます。



参考文献

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

商品詳細を見る

Beginning Ios 6 Development: Exploring the Ios SdkBeginning Ios 6 Development: Exploring the Ios Sdk
(2012/12/26)
David Mark、Jack Nutting 他

商品詳細を見る



0 Comments
Leave a comment
管理者にだけ表示を許可する
Top
0 Trackbacks
Top
Calendar
08 | 2018/09 | 10
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 - - - - - -
Recent Articles
iTunes


Swift
詳解Swift第4版(01)〜Swiftでプログラミング
詳解Swift第4版(02)〜関数
詳解Swift第4版(03)〜構造体
詳解Swift第4版(06)〜基本的なデータ型
詳解Swift第4版(07)〜パターン
詳解Swift第4版(08)〜クラスと継承
詳解Swift第4版(09)〜メモリ管理
詳解Swift第4版(10)〜拡張

詳解Swift第3版(01)〜Swiftでプログラミング
詳解Swift第3版(02)〜関数
詳解Swift第3版(03)〜構造体
詳解Swift第3版(05)〜基本的なデータ型
詳解Swift第3版(06)〜パターン
詳解Swift第3版(07)〜演算子
詳解Swift第3版(08)〜クラスと継承
詳解Swift第3版(09)〜メモリ管理
詳解Swift第3版(10)〜プロトコル
詳解Swift第3版(11)〜拡張
詳解Swift第3版(12)〜エラー処理
詳解Swift第3版(13)〜クロージャ
詳解Swift第3版(14)〜ジェネリクス

詳解Swift改訂版(01)〜Swiftでプログラミング
詳解Swift改訂版(02)〜関数
詳解Swift改訂版(03)〜構造体
詳解Swift改訂版(04)〜オプショナル
詳解Swift改訂版(05)〜基本的なデータ型
詳解Swift改訂版(06)〜パターン
詳解Swift改訂版(07)〜演算子
詳解Swift改訂版(08)〜クラスと継承
詳解Swift改訂版(09)〜メモリ管理
詳解Swift改訂版(10)〜プロトコル
詳解Swift改訂版(11)〜拡張
詳解Swift改訂版(12)〜エラー処理
詳解Swift改訂版(13)〜クロージャ
詳解Swift改訂版(14)〜ジェネリクス

詳解Swift(1)〜Swiftでプログラミング
詳解Swift(2)〜関数
詳解Swift(3)〜構造体
詳解Swift(4)〜オプショナル
詳解Swift(5)〜基本的なデータ型
詳解Swift(6)〜パターン
詳解Swift(7)〜演算子
詳解Swift(8)〜クラスと継承
詳解Swift(9)〜メモリ管理
詳解Swift(10)〜プロトコル
詳解Swift(11)〜拡張
詳解Swift(12)〜クロージャ
詳解Swift(13)〜ジェネリクス
詳解Swift(14)〜C/Objective-Cとのデータ受け渡し

文字列と文字(Swift 4)
Swift 2における文字列
Categories
Tips
WACOM


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


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
OpenGL ES
SQLite
Monthly Archives
Recent Comments
Recent TrackBacks
RSS Link
QR Code
QR
Profile

水月杏香

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

Visitors