3

サブビューを作成し、画面上でアニメーション化する簡単なプログラムがあります。

このプログラムの一環として、サブビューがタップされたときの機能を追加したいと思います。次のメソッドを使用してサブビューを作成し、UITapGestureRecognizer を追加してから、サブビューをアニメーション化しています。

int randomName = arc4random() % ([pieceNames count] - 1);
int animationDuration = arc4random() %  5 + 5 ;
NSString *randomPiece = [pieceNames objectAtIndex:randomName];

float yStart = arc4random() % 650;
float yEnd = arc4random() % 650;

UIView *piece = [[PieceView alloc]initWithFrame:CGRectMake(100.0, yStart, 75.0, 75.0)];
[piece setValue:randomPiece forKey:@"name"];

UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc]initWithTarget:self
                                                                            action:@selector(handleTouch:)];
[piece addGestureRecognizer:recognizer];

[[self view] addSubview:piece];

[UIView animateWithDuration:animationDuration
                      delay:0.0
                    options:UIViewAnimationOptionAllowUserInteraction
                 animations:^(void){
                     piece.center = CGPointMake(950.0, yEnd);
                 } completion:^(BOOL done){
                     [piece removeFromSuperview];
                 }];

タップを処理するコードは次のとおりです。

PieceView *pv = (PieceView *) recognizer.view;
NSLog(@"%@ was tapped", pv.name);

何が起こるかというと、PieceView に触れたときにプログラムが応答しません。ただし、アニメーション ブロックを削除すると、プログラムはタップに応答します。

アニメーション化されているとき、UITapGestureRecognizer が PieceView に応答しないのはなぜですか?

4

2 に答える 2

9

私はこれと同じ問題に苦しんでいましたが、要約すると、アニメーション ビューは開始位置と終了位置の 2 つの場所にしかありません。Core Animation は、ビューのレイヤーを開始点と終了点の間の補間された位置に一定期間レンダリングするだけです。

それは、星を見上げて、自分が見ていることが実際に起こっていることではないことに気付くようなものです。:)

幸いなことに、解決策は非常に簡単です。スーパービューにタップ レコグナイザーを配置し、アニメーション ビューを調べてpresentationLayer(これにより、任意の時点で正確なフレームが得られます)、タップがヒットしたかどうかを判断できます。

UIViewController問題と解決策の両方を示す単純なものを作成しました。

#import <UIKit/UIKit.h>

@interface MSMViewController : UIViewController

@end

そして実装:

#import "MSMViewController.h"

@interface MSMViewController ()
@property (nonatomic, strong) UIView *animatedView;
@end

@implementation MSMViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    CGRect startFrame = CGRectMake(125, 0, 70, 70);
    CGRect endFrame = CGRectMake(125, 400, 70, 70);

    // draw a box to show where the animated view begins
    UIView *startOutlineView = [[UIView alloc] initWithFrame:startFrame];
    startOutlineView.layer.borderColor = [UIColor blueColor].CGColor;
    startOutlineView.layer.borderWidth = 1;
    [self.view addSubview:startOutlineView];

    // draw a box to show where the animated view ends
    UIView *endOutlineView = [[UIView alloc] initWithFrame:endFrame];
    endOutlineView.layer.borderColor = [UIColor blueColor].CGColor;
    endOutlineView.layer.borderWidth = 1;
    [self.view addSubview:endOutlineView];

    self.animatedView = [[UIView alloc] initWithFrame:startFrame];
    self.animatedView.backgroundColor = [UIColor yellowColor];
    [self.view addSubview:self.animatedView];

    [UIView animateWithDuration:10 delay:2 options:UIViewAnimationOptionAllowUserInteraction animations:^{

        self.animatedView.frame = endFrame;

    } completion:nil];

    // this gesture recognizer will only work in the space where endOutlintView is
    UITapGestureRecognizer *boxTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(boxTap:)];
    [self.animatedView addGestureRecognizer:boxTap];

    // this one will work
    UITapGestureRecognizer *superviewTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(superviewTap:)];
    [self.view addGestureRecognizer:superviewTap];

}

- (void)boxTap:(UITapGestureRecognizer *)tap {
    NSLog(@"tap. view is at %@", NSStringFromCGPoint(self.animatedView.frame.origin));
}

- (void)superviewTap:(UITapGestureRecognizer *)tap {
    CGRect boxFrame = [self.animatedView.layer.presentationLayer frame];
    if (CGRectContainsPoint(boxFrame, [tap locationInView:self.view])) {
        NSLog(@"we tapped the box!");
    }
}

@end
于 2014-03-17T16:23:08.177 に答える