34

アプリ内にスプリングボードのようなインターフェイスを作成しようとしています。UIScrollView に追加された UIButtons を使用しようとしています。私が実行している問題は、ボタンがUIScrollViewにタッチを渡さないことです-フリック/スライドしようとしてボタンを押すと、UIScrollViewに登録されませんが、間のスペースをフリックするとボタンが機能します。ボタンに触れるとクリック/機能します。

ボタンがタッチ イベントをその親 (スーパービュー) に送信するように強制するプロパティまたは設定はありますか? UIScrollView を追加する前に、ボタンを別のものに追加する必要がありますか?

これが私のコードです:

//init scrolling area
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 480)];
scrollView.contentSize = CGSizeMake(480, 1000);
scrollView.bounces = NO;
scrollView.delaysContentTouches = NO;

//create background image
UIImageView *rowsBackground = [[UIImageView alloc] initWithImage:[self scaleAndRotateImage:[UIImage imageNamed:@"mylongbackground.png"]]];
rowsBackground.userInteractionEnabled = YES;

//create button
UIButton *btn = [[UIButton buttonWithType:UIButtonTypeCustom] retain];
btn.frame = CGRectMake(100, 850, 150, 150);
btn.bounds = CGRectMake(0, 0, 150.0, 150.0);
[btn setImage:[self scaleAndRotateImage:[UIImage imageNamed:@"basicbutton.png"]] forState:UIControlStateNormal];
[btn addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];

//add "stuff" to scrolling area
[scrollView addSubview:rowsBackground];
[scrollView addSubview:btn];

//add scrolling area to cocos2d
//this is just a UIWindow
[[[Director sharedDirector] openGLView] addSubview:scrollView];

//mem-mgmt
[rowsBackground release];
[btn release];
[scrollView release];
4

7 に答える 7

44

私のために働いた解決策は次のとおりです。

  1. に設定canCancelContentTouchesUIScrollViewますYES
  2. が の場合UIScrollViewにオーバーライドtouchesShouldCancelInContentView:(UIView *)viewするように拡張しています。YESviewUIButton

ドキュメントによると、touchesShouldCancelInContentViewYES表示するタッチ メッセージをさらにキャンセルし、NOビューがそれらのメッセージを受信し続けるようにします。デフォルトの戻り値はYES、ビューがUIControlオブジェクトでない場合です。それ以外の場合は、を返しますNO。」

拡張機能であるため、スクロールを有効にするにUIButtonUIControl拡張機能が必要です。canCancelContentTouches

于 2010-08-04T13:44:20.380 に答える
5

UIScrollView に多数のボタンがあり、これらのボタンをスクロールしたいという同様のケースがあります。最初に、UIScrollView と UIButton の両方をサブクラス化しました。しかし、サブクラス化した UIScrollView が touchesEnded イベントを受け取らなかったことに気付いたので、サブクラス UIButton のみに変更しました。


@interface MyPhotoButton : UIButton {
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
@end

@implementation MyPhotoButton

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesMoved:touches withEvent:event];
    [self setEnabled:NO];
    [self setSelected:NO];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    [self setEnabled:YES];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesCancelled:touches withEvent:event];
    [self setEnabled:YES];
}

@end
于 2010-04-27T09:11:58.950 に答える
1

OKここにあなたの答えがあります:

UIButton をサブクラス化します。(注: 各オーバーライドの開始時に [super ....] を呼び出します。

  • プロパティを追加します。タイプ BOOL の 1 つ (enableToRestore と呼ばれる)
  • プロパティを追加します。タイプ CGPoint の 1 つ (startTouchPosition と呼ばれる)
  • awakeFromNib と initWithFrame で、enableToRestore を isEnabled プロパティに設定します)
  • 「touchesBegan: withEvent:」をオーバーライドして、タッチ位置の開始を保存します。
  • 「touchesMoved: withEvent:」をオーバーライドして、水平方向の動きがあるかどうかを確認します。
  • YES の場合、有効を NO に設定し、NO を選択します。

サンプルコード:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{
    UITouch *touch = [touches anyObject];

    [super touchesBegan:touches withEvent:event];
    [self setStartTouchPosition:[touch locationInView:self]];
}


//
// Helper Function
//
- (BOOL)isTouchMovingHorizontally:(UITouch *)touch 
{
    CGPoint currentTouchPosition = [touch locationInView:self];
    BOOL      rValue = NO;

    if (fabsf([self startTouchPosition].x - currentTouchPosition.x) >= 2.0) 
    {
        rValue = YES;
    }

    return (rValue);
}

//
// This is called when the finger is moved.  If the result is a left or right
// movement, the button will disable resulting in the UIScrollView being the
// next responder.  The parrent ScrollView will then re-enable the button
// when the finger event is ended of cancelled.
//
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{
    [super touchesMoved:touches withEvent:event];
    if ([self isTouchMovingHorizontally:[touches anyObject]]) 
    {
        [self setEnabled:NO];
        [self setSelected:NO];
    } 
}

これにより、UIScrollView がアクティブになります。

UIScrollView をサブクラス化します。(注: 各オーバーライドの開始時に [super ....] を呼び出します。

  • 「touchesEnded: withEvent:」と「touchesCancelled: withEvent:」の両方をオーバーライドする
  • オーバーライドで、すべてのサブビュー (およびそのサブビュー) の有効化フラグをリセットします。
  • 注: カテゴリを使用して、メソッドを UIView に追加します。

.

- (void) restoreAllEnables
{
    NSArray   *views = [self subviews];

    for (UIView *aView in views)
    {
        if ([aView respondsToSelector:@selector(restoreEnable)])
        {
            [aView restoreEnable];
        }
    }
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self restoreAllEnables];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];
    [self restoreAllEnables];
}
  • カテゴリ内:

.

-(void) restoreEnable
{
    NSArray   *views = [self subviews];

    if ([self respondsToSelector:@selector(enableToRestore)])
    {
        [self setEnabled:[self enableToRestore]];
    }

    for (UIView *aView in views)
    {
        if ([aView respondsToSelector:@selector(restoreEnable)])
        {
            [aView restoreEnable];
        }
    }
}

編集注:答え3が機能することはありませんでした。同様に、setDelaysContentTouches:NO (View Controller またはどこかに設定) を設定すると、回答 4 で最良の結果が得られます。これにより、ボタンに対する応答が非常に高速になります。setDelaysContentTouches:YES を設定すると、ボタンへの応答時間に深刻な影響 (150 ミリ秒) がかかり、軽くて速いタッチができなくなります。

于 2010-02-26T02:55:46.600 に答える
1

UIScrollView 自体が多くのイベントを処理します。UIScrollView 内のボタンの touchesDidEnd とヒット テストを手動で処理する必要があります。

于 2009-03-16T14:15:38.207 に答える
0

私の経験では、最初の答え、つまり単にに設定delaysContentTouchesしてYESも、問題に関して何も変わりません。ボタンはまだスクロールビューに追跡結果を提供しません。3番目の答えは単純で非常に使いやすいものです。ありがとうsieroaoj!

delaysContentTouchesただし、3番目の回答が機能するには、もに設定する必要があります YES。それ以外の場合は、ビュー内の追跡のためにメソッドtouchesEndedも呼び出されます。したがって、次の方法で問題を解決できます。

  1. シンプルなカスタムUIViewでdeボタンを置き換えます
  2. フラグ「userInterationEnable=yes;」を設定します initメソッドについて
  3. ビューオーバーライドで、UIResponderメソッド「touchesEnded」をここでオーバーライドして、アクションをトリガーできます。

第4。delaysContentTouchesに設定YES

于 2009-11-11T09:12:48.783 に答える
0

もう 1 つの方法は次のとおり
です。 1. シンプルなカスタム UIView でボタンを
置き換えます。 2. フラグ「userInterationEnable = yes;」を置きます。init メソッド
3. ビューで UIResponder メソッド「touchesEnded」をオーバーライドすると、ボタンのように必要なアクションをトリガーできます。

于 2009-05-30T17:55:50.750 に答える