5

スクロールビューの小さなビューを含むビュー階層があります。各ビューには、ボタンなどのサブビューを含めることができます。

何らかの理由で、ビューのボタンがクリックされません。これをさらに調査すると、スクロールビューはtouchBeganイベントを受信しますが、ボタンは受信しないことがわかりました。hitTest:event:メッセージを呼び出すと、制限内であってもボタンが返されないことが示されます。

スクロールビューでのタッチの位置、hitTestから返されたアイテム、locationInViewを呼び出した場合のタッチの位置:期待されるアイテムの使用、および期待されるアイテムの階層(フレームが印刷されている)を説明するログ出力を含めました。この出力から、ボタンが呼び出されるべきだったと推測できます...

誰かがこれを説明できますか?私は何かが足りないのですか?

touched ({451, 309}) on <VCViewContainersView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>> (location in expected item: {17, 7.5})
expected touched item is:
view: <UIButtonLabel: 0x482b920; frame = (32 5; 36 19); text = 'Click'; clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x4831370>>, layer transform: [1, 0, 0, 1, 0, 0]
 view: <UIRoundedRectButton: 0x482c100; frame = (50 50; 100 30); opaque = NO; layer = <CALayer: 0x482c450>>, layer transform: [1, 0, 0, 1, 0, 0]
  view: <UIImageView: 0x480f290; frame = (0 0; 320 255); opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x480e840>>, layer transform: [1, 0, 0, 1, 0, 0]
   view: <VCViewContainer: 0x4b333c0; frame = (352 246.5; 320 471.75); layer = <CALayer: 0x4b33d50>>, layer transform: [1, 0, 0, 1, 0, 0]
    view: <UIScrollView: 0x4b32600; frame = (0 0; 1024 748); clipsToBounds = YES; autoresize = W+H; userInteractionEnabled = NO; layer = <CALayer: 0x4b32780>>, layer transform: [1, 0, 0, 1, 0, 0]
     view: <VCViewsContainerView: 0x4b31ee0; frame = (0 0; 748 1024); transform = [0, 1, -1, 0, 0, 0]; autoresize = W+H; layer = <CALayer: 0x4b32130>>, layer transform: [0, 1, -1, 0, 0, 0]
      view: <UIWindow: 0x4b1d590; frame = (0 0; 768 1024); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x4b1d6d0>>, layer transform: [1, 0, 0, 1, 0, 0]

更新UIWindowVCViewsContainerViewを除き、すべてのビューはinitWithFrame:を使用してプログラムで作成されます。ボタンの場合は、buttonWithType:を使用します。VCViewContainerはCGRectZeroを使用して初期化され、UIImageViewが作成されると、そのフレームは画像のサイズ+画像の下部にあるラベル用の追加スペースに設定されます。

アップデート2:同じ場所で[self.layer hitTest:location]を呼び出すと、正しいビューのレイヤーが表示されます。何が起きてる...?

4

3 に答える 3

5

hitTest:withEvent: ウィンドウで開始します。各ビューは、それ自体をテストする前にサブビューをテストするなど、再帰的にテストします。ただし、ビューの userInteractionEnabled が NO の場合、サブビューをテストせずに、hitTest:withEvent: から nil を返します。そのようなビューは確かにヒット テストされますが、そのビューもそのサブビューもヒット ビューではないとすぐに応答します。

UIScrollView の userInteractinonEnabled は NO に設定されています。したがって、VCViewContainersView がそのサブビュー UIScrollView をテストし、userInteractionEnabled が NO であるため UIScrollView が nil を返す場合、VCViewContainersView はそれ自体で pointInside:withEvent: を使用し、タッチがそれ自体の内部にあることを検出し、ヒット ビュー (および検索は終了します)。これは、あなたが得ている結果を説明しています。

レイヤーを介してヒットテストを実行するときにこれが発生しない理由は、レイヤーがタッチ可能ではなく、タッチのルールについて何も知らないため、レイヤー機能ではなくビュー機能である userInteractionEnabled を無視するためです。レイヤーのヒットテストは、ビューにレイヤー階層全体 (ビュー階層なし) が含まれており、特定のレイヤーがタッチ可能であることをシミュレートしたい場合のみを対象とした、一種のクラッジです。ドキュメントは、レイヤーの hitTest: のロジックはビューの hitTest:withEvent: のロジックとは異なることを示していますが、正確な方法については説明していません。

スクロールビューをタッチ不可に設定した理由はわかりませんが、それが重要な場合は、 UIScrollView サブクラスで hitTest:withEvent: をオーバーライドして、サブビューをテストしますが、すべてが返された場合は nil を返すことができますなし。

于 2010-10-28T01:18:38.077 に答える
1

UIScrollView をサブクラス化して、その中のオブジェクトへのタッチを受け取ることができます。

デフォルトでは、タッチは UIScrollView によって受信されるため、その中のオブジェクトへのタッチを受信する場合は、明示的に設定する必要があります。

これはまさにそれを行うための実用的なサブクラスです。これについて SO コミュニティに感謝します。もともとここでこのようなものを見つけたと信じているため、元の投稿を今は掘り下げることができません。

.h は次のとおりです。

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface TouchScroller : UIScrollView 
{
}

@end

そして.m:

#import "TouchScroller.h"


@implementation TouchScroller

- (id)initWithFrame:(CGRect)frame 
{
return [super initWithFrame:frame];
}

- (void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event 
{   
// If not dragging, send event to next responder
if (!self.dragging) 
    [self.nextResponder touchesEnded: touches withEvent:event]; 
else
    [super touchesEnded: touches withEvent: event];
}

@end

それはそれを行う必要があります。

于 2011-05-27T20:17:23.727 に答える
0

ビュースタックを正しく理解している場合、ボタンはUIImageViewのサブビューです-userInteractionEnabledプロパティがNOに設定されています(デフォルト)-したがって、画像ビューとそのすべてのサブビューはタッチイベントを受け取りません。

画像ビューのuserInteractionEnabledプロパティをに設定YESすると、問題を解決する必要があります

于 2010-10-22T10:36:12.523 に答える