5

キーボードを想像してみてください。1 本の指を 1 つのキーに置き、(押したまま) 指をキーボードの別のキーに移動することを想像してみてください。ここで、キーボードの各キーがUIButton. 現在のキーを指で押さえていると、このキー ( UIButton) が強調表示されます。次に、ユーザーが別のキーに移動すると、最初のキーは強調表示されなくなり、現在押されているキーが強調表示されます。

これで、各 53 x 53 ピクセルの UIButton の 6 x 8 グリッドができました。だから、私は 48 を持っていUIButtonsます。こういう発想は真似したい。ユーザーの指が置かれているボタンの画像は (選択されているように) わずかに明るくなり、他のすべてのボタンはわずかに明るくなりません。

これについての私の考えは次のとおりです。

1) で 48 個すべてを作成しUIButtonsますviewDidLoadUIControlStateHighlightedfor allに明るいイメージを追加しますUIButtons

2)現在のボタンを強調表示せず、使用できないようにするtargetための何らかの種類を追加します。touchUpOutside(ハイライトされた とuserInteractionEnabledno を設定するかもしれません)。しかし、次のボタンが使用されるようにするにはどうすればよいでしょうか? UIButtonそして、ユーザーの指が下にある特定のものを強調表示し、ジェスチャーやものを検出するために使用する必要があるとどのように言うことができますか。

また、touchUpOutsideすべてのボタンが互いに隣り合っているため、この方法は機能しない可能性があり、これを実行するには遠くまでドラッグする必要があると思いますtouchUpOutside.

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

4

2 に答える 2

4

2 つの観察:

  1. 私は通常、さまざまな方法ではなく、このようなものにジェスチャ認識機能を使用しtouchUp...ます。

  2. サブビューを高速に列挙したくないと言ったのは知っていますが、なぜですか? 一部のクラスが他のクラスと異なるという理由だけで、問題はありません (メソッドをテストするだけでよいためisKindOfClass)。(余談ですが、なぜボタンになるものとそうでないものがあるのか​​はわかりません。) 並べていないからといって、実際には何の違いもありません。

とにかく、このようなものについては、ジェスチャ認識機能を共有の親ビュー (通常はビュー コントローラーのビューなど) に頻繁に配置し、サブビューを列挙して現在の 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;
    }
}

これがあなたにとって意味があるかどうかはわかりませんが、私には最も簡単に思えます。意図を明確にしていただければ、回答をさらに絞り込むことができるかもしれません。

実用的な例として、クリックされた最初と最後のサブビューを追跡する継続的なジェスチャ認識エンジンを定義できます (サブビューでジェスチャを開始しない場合、ジェスチャは生成されません。サブビューでジェスチャを停止すると、すべてがキャンセルされます)、例:

@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

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

次に、ハンドラーをそのように定義します (これはボタンと画像ビューで機能し、両方が をサポートしているという事実を利用します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");
    }
}
于 2012-08-12T03:25:27.287 に答える
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:電話の着信や画面のロックなど、何かがアプリを中断したことを検出します

于 2012-08-12T06:20:44.233 に答える