UIPinchGestureRecognizer选择器未在UIImageView上调用 [英] UIPinchGestureRecognizer selector not getting called on UIImageView

查看:72
本文介绍了UIPinchGestureRecognizer选择器未在UIImageView上调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经尝试了好几个小时,在这里完全不知所措.我正在尝试为我的游戏中的某些自定义UIImageViews实现UIPinchGestureRecognizer,但是它不起作用.我研究过的所有内容都说它应该起作用,但事实并非如此.如果将捏添加到我的视图控制器或自定义UIView(而不是UIImageViews)中,则Pinch可以正常工作.我尝试了所有常见的修复和调整,但均未成功.我将userInteractionEnabledmultipleTouchEnabled设置为YES.我已经正确设置了委托和选择器.我已将shouldRecognizeSimultaneouslyWithGestureRecognizer设置为返回是".

手势识别器已添加到UIImageView中,稍后我可以在更新循环中访问其属性,但是当我尝试捏住时,选择器中的NSLog永远不会被UIImageView调用.我已经调整了视图的z位置,以确保它们在顶部但没有骰子.

我的UIImageViews存储在NSMutableDictionary中,并在游戏的每次更新循环中通过循环循环进行更新.这可能会对未调用UIPinchGestureRecognizer产生影响吗?...我想不起其他任何事情,发布代码可能也无济于事-因为当将相同的代码用于UIView或视图控制器时,该代码完全相同./p>

我在视图控制器的touchesBegan和touchedMoved事件中确实有触摸处理代码...但是我已将其关闭,但问题仍然存在,并且无论如何,捏合对于其他元素都是有效的.

有什么想法可以阻止手势选择器在UIImageView上触发?词典?与在游戏循环中不断更新有关?任何想法都会受到欢迎,实现起来似乎很简单...

这是UIImageView的代码以及我正在使用的代码...不确定是否有帮助.

扩展的UIImageView类Paper.m(prp是用于初始化自定义变量的属性的struct:

NSString *tName =  [NSString stringWithUTF8String: prp.imagePath];
UIImage *tImage = [UIImage imageNamed:[NSString stringWithFormat:@"%@.png",tName]];
self = [self initWithImage: tImage];
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = YES;
self.center = CGPointMake(prp.spawnX, prp.spawnY);
if (prp.zPos != 0)  { self.layer.zPosition = prp.zPos; }
// other initialization excised

然后,我有一个名为ObjManager的自定义类,该类包含NSMutableDictionary并初始化所有UIImageView对象,像这样,在循环中调用addObj以添加每个对象:

- (ObjManager*) initWithBlank {
    // create an array for our objects
    self = [super init];
    if (self) {
        objects = [[NSMutableDictionary alloc] init];
        spawnID = 100;  // start of counter for dynamically spawned object IDs
    }
    return self;
}

- (void) addObj:(Paper *)paperPiece wasSpawned:(BOOL)spawned {
    // add each paper piece, assign spawnID if dynamically spawned
    NSNumber *newID;
    if (spawned) { newID = [NSNumber numberWithInt:spawnID]; spawnID++; }
    else         { newID = [NSNumber numberWithInt:paperPiece.objID]; }
    [objects setObject:paperPiece forKey:newID];
}

我的视图控制器调用ObjManager的初始化(在我的VC中称为_world).然后像这样循环遍历_world:

// Populate additional object managers and add all subviews
for (NSNumber *key in _world.objects) {

    _eachPiece = [_world.objects objectForKey:key];

    // Populate collision object manager
    if (_eachPiece.collision) {
        [_world_collisions addObj:_eachPiece wasSpawned:NO];
    }

    // only add pinch gesture if the object flag is set
    if (_eachPiece.pinch) {  
        UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchPaper:)];
        pinchGesture.delegate = self;
        [_eachPiece addGestureRecognizer:pinchGesture];
        NSLog(@"Added pinch recognizer scale: %@", pinchGesture.view.description);
    }

    // Add each object as a subview
    [self.view addSubview:_eachPiece];

}

_eachPiece是我的视图控制器中的一个对象,在.h文件中声明(与_world一样):

@property (nonatomic, strong) ObjManager *world; 
@property (nonatomic, strong) Paper *eachPiece;

然后我有一个NSTimer对象,它每帧更新_world(ObjManager)中的所有可移动Paper对象(UIImageViews):

// loop through each piece and update
for (NSNumber *key in _world.objects) {

    eachPiece = [_world.objects objectForKey:key];

    // only update moveable pieces
    if ((eachPiece.moveType == Move_Touch) || (eachPiece.moveType == Move_Auto)) {

        CGPoint paperCenter;
        paperCenter = eachPiece.center;

        // a bunch of code to update paperCenter x & y for the object's new position based on velocity and user input

        // determine image direction and transformation matrix
        [_world updateDirection:eachPiece];
        CGAffineTransform transformPiece = [_world imageTransform:eachPiece];
        if (transformEnabled) {
            eachPiece.transform = transformPiece;
        }

        // finally move it
        [eachPiece setCenter:paperCenter];

    }

}

和捏选择器:

- (void)pinchPaper:(UIPinchGestureRecognizer *)recognizer {
    NSLog(@"Pinch scale: %f", recognizer.scale);
    recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
    recognizer.scale = 1;
}

据我所知,捏应该起作用.如果我使用相同的捏合手势代码并将其设置为添加到视图控制器,则它适用于整个视图.我还有一个自定义的UIView类,它充当边框(只是在视图周围绘制了一个矩形),并将捏合手势代码移动到该位置使我只能捏捏边框.

解决方案

好的,因此,显然手势识别器不会在对位置进行动画处理的视图上触发.因此,要使其正常工作,我必须将识别器放在视图控制器上,然后执行命中测试,并在触摸的视图上进行缩放/缩放(如果要缩放/缩放).此处的信息:

http://iphonedevsdk.com/forum/iphone- sdk-tutorials/100982-caanimation-tutorial.html

对于我的特殊情况,我在视图控制器"级别的变量/数组中跟踪了要缩放的动画视图.然后,我在选择器中使用了这段代码(基本上是从上面的链接中获得的,全部归功于他们):

- (void)pinchPaper:(UIPinchGestureRecognizer *)recognizer {

    CALayer *pinchLayer;
    id layerDelegate;
    CGPoint touchPoint = [recognizer locationInView:self.view];

    pinchLayer = [self.view.layer.presentationLayer hitTest: touchPoint];
    layerDelegate = [pinchLayer delegate];

    //_pinchView is the UIView I want to pinch
    if (layerDelegate == _pinchView) {
        _pinchView.transform = CGAffineTransformScale(_pinchView.transform, recognizer.scale, recognizer.scale);
        recognizer.scale = 1;
    }
}

唯一棘手的事情是,如果在现有的UIView动画中进行其他比例转换(例如更改我的方向),则必须在每个更新循环中使用当前的转换来解决这个问题.

I've been trying to figure this out for hours, completely at a loss here. I'm trying to implement a UIPinchGestureRecognizer for some of the custom UIImageViews in my game, but it doesn't work. Everything thing I've researched says it should work, yet it doesn't. Pinch works fine if I add it to my view controller, or to a custom UIView, but not the UIImageViews. I've tried all the common fixes and tweaks, to no success. I have userInteractionEnabled and multipleTouchEnabled set to YES. I have the delegate and selectors set up properly. I have shouldRecognizeSimultaneouslyWithGestureRecognizer set to return YES.

The gesture recognizer is getting added to the UIImageView, I've been able to access its properties later in my update loop, but the NSLog in the selector never gets called for the UIImageView when I try to pinch. I've adjusted the z-position of the views to ensure they are on top but no dice.

My UIImageViews are stored in a NSMutableDictionary and are updated by looping through it during each update loop of the game. Could this have an effect on the UIPinchGestureRecognizer not getting called?... I can't think of anything else and posting the code probably won't help - because the same exact code works when it's used for the UIView or view controller.

I do have touch handling code in the view controller's touchesBegan and touchedMoved events... but I've turned that off but the problem still persists, and the pinch worked for other elements with it on anyway.

Any ideas what could prevent a gesture selector from firing on an UIImageView? The dictionary? Something to do with being constantly updated in the game loop? Any ideas would be welcome, this seems so simple to implement...

Edit: Here's the code for the UIImageView and what I'm doing with it... not sure if this helps.

Extended UIImageView class Paper.m (prp is a struct of properties used to initialize my custom variables:

NSString *tName =  [NSString stringWithUTF8String: prp.imagePath];
UIImage *tImage = [UIImage imageNamed:[NSString stringWithFormat:@"%@.png",tName]];
self = [self initWithImage: tImage];
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = YES;
self.center = CGPointMake(prp.spawnX, prp.spawnY);
if (prp.zPos != 0)  { self.layer.zPosition = prp.zPos; }
// other initialization excised

Then I have a custom class called ObjManager that holds the NSMutableDictionary and initializes all UIImageView objects like so, where addObj is called in a loop to add each object:

- (ObjManager*) initWithBlank {
    // create an array for our objects
    self = [super init];
    if (self) {
        objects = [[NSMutableDictionary alloc] init];
        spawnID = 100;  // start of counter for dynamically spawned object IDs
    }
    return self;
}

- (void) addObj:(Paper *)paperPiece wasSpawned:(BOOL)spawned {
    // add each paper piece, assign spawnID if dynamically spawned
    NSNumber *newID;
    if (spawned) { newID = [NSNumber numberWithInt:spawnID]; spawnID++; }
    else         { newID = [NSNumber numberWithInt:paperPiece.objID]; }
    [objects setObject:paperPiece forKey:newID];
}

My view controller calls the initialization of the ObjManager (called _world in my VC). Then it loops through _world like so:

// Populate additional object managers and add all subviews
for (NSNumber *key in _world.objects) {

    _eachPiece = [_world.objects objectForKey:key];

    // Populate collision object manager
    if (_eachPiece.collision) {
        [_world_collisions addObj:_eachPiece wasSpawned:NO];
    }

    // only add pinch gesture if the object flag is set
    if (_eachPiece.pinch) {  
        UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchPaper:)];
        pinchGesture.delegate = self;
        [_eachPiece addGestureRecognizer:pinchGesture];
        NSLog(@"Added pinch recognizer scale: %@", pinchGesture.view.description);
    }

    // Add each object as a subview
    [self.view addSubview:_eachPiece];

}

_eachPiece is an object in my view controller, declared in the .h file (as is _world):

@property (nonatomic, strong) ObjManager *world; 
@property (nonatomic, strong) Paper *eachPiece;

Then I have an NSTimer object that updates all moveable Paper objects (the UIImageViews) in _world (ObjManager) every frame like so:

// loop through each piece and update
for (NSNumber *key in _world.objects) {

    eachPiece = [_world.objects objectForKey:key];

    // only update moveable pieces
    if ((eachPiece.moveType == Move_Touch) || (eachPiece.moveType == Move_Auto)) {

        CGPoint paperCenter;
        paperCenter = eachPiece.center;

        // a bunch of code to update paperCenter x & y for the object's new position based on velocity and user input

        // determine image direction and transformation matrix
        [_world updateDirection:eachPiece];
        CGAffineTransform transformPiece = [_world imageTransform:eachPiece];
        if (transformEnabled) {
            eachPiece.transform = transformPiece;
        }

        // finally move it
        [eachPiece setCenter:paperCenter];

    }

}

And the pinch selector:

- (void)pinchPaper:(UIPinchGestureRecognizer *)recognizer {
    NSLog(@"Pinch scale: %f", recognizer.scale);
    recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
    recognizer.scale = 1;
}

As far as I can tell, the pinch should work. If I take the same pinch gesture code and set it to add to the view controller, it works for the entire view. I also have a custom UIView class that acts as a border (simply a rectangle drawn around the view), and moving the pinch gesture code to that allows me to pinch the border only.

解决方案

Alright, so apparently gesture recognizers don't fire on views where the position is being animated. So to make it work I had to put the recognizer on the view controller, then perform a hit test and apply pinch/zoom on the touched view if it's one I want to pinch/zoom. Info on that here:

http://iphonedevsdk.com/forum/iphone-sdk-tutorials/100982-caanimation-tutorial.html

For my particular case, I kept track of which animated views I wanted to pinch, in a variable/array at the View Controller level. Then I used this code in the selector (essentially from the link above, all credit to them):

- (void)pinchPaper:(UIPinchGestureRecognizer *)recognizer {

    CALayer *pinchLayer;
    id layerDelegate;
    CGPoint touchPoint = [recognizer locationInView:self.view];

    pinchLayer = [self.view.layer.presentationLayer hitTest: touchPoint];
    layerDelegate = [pinchLayer delegate];

    //_pinchView is the UIView I want to pinch
    if (layerDelegate == _pinchView) {
        _pinchView.transform = CGAffineTransformScale(_pinchView.transform, recognizer.scale, recognizer.scale);
        recognizer.scale = 1;
    }
}

Only tricky thing is if you have other scale transforms (like changing directions in mine) going on as part of the existing UIView animation, you have to account for that, by using the current transform during each update loop.

这篇关于UIPinchGestureRecognizer选择器未在UIImageView上调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆