あなたが話していることを理解しやすくするために、任意の図面をダウンロードして(たとえば、 Bamboo Paper 、 アプリケーションは私のものではありません、無料 )、画面の自動回転をブロックし、小さな水平線を描画してから、デバイスを裏返しにして(自動回転をロックするときに必要)、描画された線を続けてみてください。 ほとんどの場合、継続行は元の行よりも下になります。
ほとんどのアプリケーションでは、この動作は目に見えませんが、一部のアプリケーションでは有害な場合があります。 たとえば、自動回転がオフになっていて、ユーザーが好きなようにデバイスを回転できると想定されるスケッチでは、デバイスの現在の回転に関係なく、同一のタッチ処理を保証する必要があります。 または、チェスなどのボードゲームでは、座標の変化によりプレイヤーが黒を再生する可能性があります(ポートレートモードのインターフェイスが逆さまになっている場合)。ピースを移動しようとすると、下のセルからピースを逃してしまいます。
第一世代のiPadでの私のテストによると、シフトは約7ピクセルでした。 当然、他のデバイスでは結果が異なりますので、テストする必要があります。
Appleのドキュメントには、この移行を管理するためのオープンソフトウェアインターフェイスが見つからなかったため、回避策を探す必要がありました。
スケッチの場合、 touchesMovedメソッドなどのロジックに修正を簡単に導入できます。
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { //... CGPoint point = [[touches anyObject] locationInView:self]; // , .. y point.y = point.y + 7; //... }
ただし、これは常に受け入れられるとは限りません。特に、変更せずに再利用したい既製のコードがある程度ある場合はそうです。
根本的な解決策として、この記事の最初のバージョンでは、 UITouchインスタンスのlocationInViewおよびpreviousLocationInViewへの絶対的にすべての呼び出しの修正を含む例を示しました。
#import "objc/runtime.h" @interface UITouch (Adjusted) -(CGPoint)adjustedLocationInView:(UIView *)view; -(CGPoint)adjustedPreviousLocationInView:(UIView *)view; @end @implementation UITouch (Adjusted) -(CGPoint)adjustedLocationInView:(UIView *)view{ CGPoint point = [self adjustedLocationInView:view]; point.y = point.y + 7; return point; } -(CGPoint)adjustedPreviousLocationInView:(UIView *)view{ CGPoint point = [self adjustedPreviousLocationInView:view]; point.y = point.y + 7; return point; } +(void)load{ Class class = [UITouch class]; Method locInViewMethod = class_getInstanceMethod(class, @selector(locationInView:)); Method adjLocInViewMethod = class_getInstanceMethod(class, @selector(adjustedLocationInView:)); method_exchangeImplementations(locInViewMethod, adjLocInViewMethod); Method prevLocInViewMethod = class_getInstanceMethod(class, @selector(previousLocationInView:)); Method adjPrevLocInViewMethod = class_getInstanceMethod(class, @selector(adjustedPreviousLocationInView:)); method_exchangeImplementations(prevLocInViewMethod, adjPrevLocInViewMethod); NSLog(@"UITouch class is adjusted now."); } @end
ここでは、ランタイム関数method_exchangeImplementationsを使用して、デフォルトUITouchメソッドの実装を修正して交換します。 カテゴリが作成されたファイルは、他の.hまたは.mファイルにインポートする必要がないことに注意してください。 プロジェクトに追加するだけで、 + loadメソッドが自動的に呼び出されます。 +ロードメッセージは、ランタイムに追加するときに各クラスおよびカテゴリに自動的に送信されます。
更新しました。 ただし、 コメント 5 で判明したように 、iOS 5以降、Apple はアプリケーションでmethod_exchangeImplementations を使用しないように求めています。 情報をいただきありがとうございます。 したがって、修正を行うには、たとえば、コメントで提案されている方法のいずれかなど、好みに応じて他の方法を使用することをお勧めします。
したがって、修正の導入後、ビューの描画は、デバイスのどの方向でも同じように機能します。 ただし、これはチェスの駒の問題を解決しません。タッチイベントを送信するビューを決定するときに、シフトポイントが使用され、間違った駒になる可能性があります。
タッチを処理するビューを決定するには、 UIViewでhitTest:withEvent:メソッドを使用します。これは次のように機能します。
- pointInside:withEvent:は self で呼び出されます。
- 結果がNOの場合、 hitTest:withEvent:はnilを返します。 ビューはタッチに反応しません。
- 結果がYESの場合、メソッドはhitTest:withEvent:をすべてのサブビューに再帰的に送信します。
- サブビューの1 つが非 nilオブジェクトを返した場合、ルートhitTest:withEvent:はこのオブジェクトを返します。
- すべてのサブビューがnilを返した場合、またはビューにサブビューがない場合、 selfが返されます。
したがって、タッチが正しくチェスの駒に入るには、すべてのサブビューを含むルートビューのhitTest:withEventを再定義するだけで十分です。このため、修正を導入する必要があります。
@implementation ChessBoardView - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event { point.y = point.y + 7; UIView *hitView = [super hitTest:point withEvent:event]; return hitView; } @end
その後、黒をプレイするプレイヤーは白をプレイするプレイヤーと同じくらい便利にチェスの駒になります。