2012-08-12 5 views
5

キーボードを想像してみてください。 1つのキーを1つのキーの下に置いて、次に(指を押しながら)指をキーボードの別のキーまでずっと動かしているとします。今、キーボードの各キーがUIButtonであるとします。現在のキーを指で押さえているときは、このキー(UIButton)が強調表示されます。次に、ユーザーが別のキーに移動すると、最初のキーは強調表示されなくなり、現在押し下げられているキーが強調表示されます。指を押し下げたまま、UIButtonを別のUIButtonに切り替えるにはどうしたらいいですか?

今、53 x 53ピクセルのUIButtonsが6 x 8グリッドあります。だから、私はを持っています。私はこの種のアイデアを再現したい。ユーザーの指が置かれているボタンは、(選択されたように見えるように)わずかに明るい画像を持ち、他のものはわずかに明るくなりません。ここで

この、

1については移動する方法の私の考えである)viewDidLoadに全48 UIButtonsを作成します。明るい画像をUIButtonsの場合はUIControlStateHighlightedに追加してください。

2)touchUpOutsideに何らかの種類のtargetを追加すると、何らかの理由で現在のボタンが強調表示されず、使用できなくなります。 (強調表示され、userInteractionEnabledをnoに設定することもできます)。しかし、次に使用する次のボタンをどのように伝えることができますか?そして、私は特定のUIButtonを、ユーザーの指が強調表示され、ジェスチャーやものを検出するために使用されるようにしたいと言うことができます。

また、このtouchUpOutsideメソッドは、すべてのボタンがすぐ隣にあるため機能しない可能性があります。これを実行するには遠くにドラッグする必要があると思います。touchUpOutside

ボタンが同じ行と列に配置されていないことにも注意してください。ボタン1つが実際にはUIImageになりますが、UIButtonのように見えることがあります。だから何らかの理由でフレームを比較する何らかの高速列挙をすることはできません。

+0

あなたはいくつかの低レベルの動作(あなたが指を押して別のボタンにドラッグすると解決しますが、あなたが解決しようとしているより広い問題は説明していないので、あなたの質問に少し答えるタフ。あなたは何をしようとしているのですか?ワンタッチでタッチを検出し、別のボタンでタッチアップするだけですか? Swypeのようなタイピングスキームのシリーズ全体ですか?提案された回答は、あなたがしようとしていることに依存するかもしれません。 – Rob

+0

私はまた、フレームワークの高速列挙ではないことについて最後の点を理解していません。なぜなら、異なるサブビュータイプについて心配している場合、正しい動作が何であったかを知るために 'isKindOfClass'をチェックするだけだからです。私の答えを見てください。 – Rob

+0

UIImageの代わりにUIImageViewを使用すると仮定します – WolfLink

答えて

4

2つの観測:

  1. 私は、一般的にこのようなもののためのジェスチャー認識装置、ではない様々なtouchUp...メソッドを使用します。

  2. あなたはサブビューを通して高速列挙を望んでいないと言いましたが、どうしてですか?他のクラスとは異なるクラスがあるからといって、問題はありません(isKindOfClassメソッドをテストするだけなので)。なぜなら、彼らが並んでいないからといって、本当に違いはないからです。

とにかく、このようなもののために、私は頻繁に共有親ビュー(例えば、通常View Controllerのビュー)にジェスチャー認識を置く、その後、現在するCGPointが含まれている見ることがサブビューを列挙します?

CGPoint location = [sender locationInView:self.view]; 

for (UIView *subview in self.view.subviews) 
{ 
    if (CGRectContainsPoint(subview.frame, location)) 
    { 
     // do your appropriate highlighting 

     if ([subview isKindOfClass:[UIButton class]]) 
     { 
      // something for buttons 
     } 
     else if ([subview isKindOfClass:[UIImageView class]]) 
     { 
      // something for imageviews 
     } 

     return; 
    } 
} 

これがあなたにとって意味をなさすかどうかわかりませんが、私にとっては最も簡単です。あなたの意図を明確にすれば、おそらく私は自分の答えをさらに洗練することができます。

実際の例のように、クリックされた最初と最後のサブビューを追跡する連続ジェスチャ認識プログラムを定義することができます(サブビューでジェスチャーを開始しないと、ジェスチャーは生成されません。

SubviewGestureRecognizer *recognizer = [[SubviewGestureRecognizer alloc] initWithTarget:self action:@selector(handleTouches:)]; 
[self.view addGestureRecognizer:recognizer]; 

をそして、としてあなたのハンドラを定義します。

@interface SubviewGestureRecognizer : UIGestureRecognizer 

@property (nonatomic,strong) UIView *firstSubview; 
@property (nonatomic,strong) UIView *currentSubview; 

@end 

@implementation SubviewGestureRecognizer 

- (id) initWithTarget:(id)target action:(SEL)action 
{ 
    self = [super initWithTarget:target action:action]; 
    if (self) 
    { 
     self.firstSubview = nil; 
     self.currentSubview = nil; 
    } 

    return self; 
} 

// you might want to tweak this `identifySubview` to only look 
// for buttons and imageviews, or items with nonzero tag properties, 
// or recursively navigate if it encounters container UIViews 
// or whatever suits your app 

- (UIView *)identifySubview:(NSSet *)touches 
{ 
    CGPoint location = [[touches anyObject] locationInView:self.view]; 

    for (UIView *subview in self.view.subviews) 
    { 
     if (CGRectContainsPoint(subview.frame, location)) 
     { 
      return subview; 
     } 
    } 

    return nil; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesBegan:touches withEvent:event]; 

    if ([touches count] != 1) 
    { 
     self.state = UIGestureRecognizerStateFailed; 
     return; 
    } 

    self.firstSubview = [self identifySubview:touches]; 
    self.currentSubview = self.firstSubview; 

    if (self.firstSubview == nil) 
     self.state = UIGestureRecognizerStateFailed; 
    else 
     self.state = UIGestureRecognizerStateBegan; 
} 

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    [super touchesMoved:touches withEvent:event]; 

    if (self.state == UIGestureRecognizerStateFailed) return; 

    self.currentSubview = [self identifySubview:touches]; 

    self.state = UIGestureRecognizerStateChanged; 
} 

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

    self.currentSubview = [self identifySubview:touches]; 

    if (self.currentSubview != nil) 
     self.state = UIGestureRecognizerStateEnded; 
    else 
     self.state = UIGestureRecognizerStateFailed; 
} 

- (void)reset 
{ 
    [super reset]; 

    self.firstSubview = nil; 
    self.currentSubview = nil; 
} 

あなたはその後、viewDidLoadでこれを設定することができます:あなたがサブビューにあなたのジェスチャーを停止しない場合、それは例えば、)全部をキャンセルそのような(これは、ボタンと画像ビューで動作し、両方ともサポートsetHighlighted)の利点:

- (void)handleTouches:(SubviewGestureRecognizer *)sender 
{ 
    static UIControl *previousControl = nil; 

    if (sender.state == UIGestureRecognizerStateBegan || sender.state == UIGestureRecognizerStateChanged) 
    { 
     if (sender.state == UIGestureRecognizerStateBegan) 
      previousControl = nil; 

     UIView *subview = sender.currentSubview; 
     if (previousControl != subview) 
     { 
      // reset the old one (if any) 

      [previousControl setHighlighted:NO]; 

      // highlight the new one 

      previousControl = (UIControl *)subview; 
      [previousControl setHighlighted:YES]; 
     } 
    } 
    else if (sender.state == UIGestureRecognizerStateEnded) 
    { 
     if (previousControl) 
     { 
      [previousControl setHighlighted:NO]; 
      NSLog(@"successfully touchdown on %@ and touchup on %@", sender.firstSubview, sender.currentSubview); 
     } 
    } 
    else if (sender.state == UIGestureRecognizerStateCancelled || sender.state == UIGestureRecognizerStateFailed) 
    { 
     [previousControl setHighlighted:NO]; 
     NSLog(@"cancelled/failed gesture"); 
    } 
} 
+0

さて、私はこのようにするのは少し躊躇しています。ユーザーが指を動かすと、瞬間的になりたいからです。そして、私が小さな小さなドラッグを行うたびにこのメソッドを実行すると、問題が発生する可能性が高いと思います。 – bmende

+0

私はあなたが瞬時に見つけることができると思うが、明らかに他のアプローチを追求する。しかし、最も基本的なレベルでは、これらのテクニックのすべてでは、おそらく同じUIResponderメソッド、touchesBegan'、 'touchesMoved'、' touchedEnded'などを使用していると思いますので、違いを生むちなみに、私はあなたのタッチハンドラルーチンでは少し洗練されているので、 "どのサブビューは私が終わったのか"のロジックをたくさん隠しているカスタムジェスチャ認識プログラムで自分の答えを更新しました。しかし、あなたが好きなように別のテクニックを見つけたならば、確かにここでは犯行はありません。 – Rob

+2

@Sasquatch何千ものボタンがない限り、私は心配しません。早期の最適化がルートです... –

0

これはかなり簡単な方法です。プログラムでボタンを作成していると仮定します(インターフェースビルダーでこれを行うのは非常に苦しいでしょう)。このメソッドは、UIViewController、UIView、およびUIGestureRecognizerのサブクラスで機能します。

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

    //get the touch object 
    UITouch *myTouch = [touches anyObject]; 

    //get the location of the touch 
    CGPoint *myPoint = [myTouch locationInView:self.view]; 

    //detect if the touch is in one of your buttons 
    if (CGRectContainsPoint(myButton.frame, myPoint){ 
     /*do whatever needs to be done when the button is pressed 
     repeat the CGRectContainsPoint for all buttons, 
     perhaps using a while or for loop to look through an array?*/ 
    } 

} 

このメソッドは、ユーザーだけが自分の指を下に置くとき、あなたは他の動きを検出するために、これらのメソッドを使用する必要があります検出します

touchesMoved:withEvent

を持ち上げることなく画面全体でたときに指の動きを検出し、

touchesEnded:withEventは、指が画面から持ち上げられたときを検出します。

touchesCancelled:withEvent:コールの受信や画面のロックなど何かがアプリを中断したときを検出します。

関連する問題