长按后滑动

时间:2014-07-30 20:09:12

标签: ios objective-c swipe long-press

好的,所以我正在帮助将Android游戏转换为iOS。该游戏基于2048年,但使用字母而不是数字。我有一点工作但仍在学习Objective C / iOS怪癖。到目前为止,我有瓷砖/网格工作,运动工作等,但我需要一点帮助。目标是允许用户长按瓷砖以选择它,然后将他们的手指滑动到相邻的瓷砖以开始拼写单词。我已经实施了长按部分,但我对如何长按然后滑动有点不知所措。除此之外,我已经有一个滑动,允许用户移动瓷砖。在这里搜索我已经看到了关于子类化的建议所以我想我需要继承UISwipeGestureRecognizer方法。我已经放入了同时手势识别器,但不确定从哪里开始。

所以,这有几个问题。

  1. 最好的方法是什么?实现每个UISwipeGestureRecognizer

  2. 的子类
  3. 我当前的滑动检测是否会干扰? (现在刷卡本身会在滑动方向上移动瓷砖)

  4. 我猜我需要做一个(如果长按)然后激活子类滑动方法?

  5. 回答上述问题的任何例子都会有很大帮助。我不是要求你为我做这件事,但至少要指出我的方向。谢谢!

  6. 以下代码。

    //  Grid.m
    #import "Grid.h"
    #import "Tile.h"
    
    - (void)didLoadFromCCB {
        // listen for swipes to the left
        UISwipeGestureRecognizer * swipeLeft= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeLeft)];
        swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
        [[[CCDirector sharedDirector] view] addGestureRecognizer:swipeLeft];
    
        // listen for swipes to the right
        UISwipeGestureRecognizer * swipeRight= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeRight)];
        swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
        [[[CCDirector sharedDirector] view] addGestureRecognizer:swipeRight];
    
        // listen for swipes up
        UISwipeGestureRecognizer * swipeUp= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeUp)];
        swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
        [[[CCDirector sharedDirector] view] addGestureRecognizer:swipeUp];
    
        // listen for swipes down
        UISwipeGestureRecognizer * swipeDown= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:@selector(swipeDown)];
        swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
        [[[CCDirector sharedDirector] view] addGestureRecognizer:swipeDown];
    
        // listen for long press
        UILongPressGestureRecognizer *longpress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(onLongPress:)];
        [longpress setMinimumPressDuration:0.5];
        [[[CCDirector sharedDirector] view] addGestureRecognizer:longpress];
    }
    
    - (void)swipeLeft {
        [self move:ccp(-1, 0)];
    }
    - (void)swipeRight {
        [self move:ccp(1, 0)];
    }
    - (void)swipeDown {
        [self move:ccp(0, -1)];
    }
    - (void)swipeUp {
        [self move:ccp(0, 1)];
    }
    
    // detect longpress, convert to NodeSpace and check if touch location is within tile boundingbox. If yes, set background white, text black.
    - (void)onLongPress:(UILongPressGestureRecognizer *) recognizer {
        CGPoint touchPoint = [[CCDirector sharedDirector] convertToGL:[recognizer locationInView:[recognizer view]]];
        touchPoint = [self convertToNodeSpace:touchPoint];
    
        if (recognizer.state == UIGestureRecognizerStateBegan) {
            for (Tile *tile in self.children) {
                if([tile isKindOfClass:[Tile class]]) {
    
                    CGRect tileBoundingBox = tile.boundingBox;
                    if (CGRectContainsPoint(tileBoundingBox, touchPoint)) {
    
                        tile.backgroundNode.color = [CCColor whiteColor];
                        tile.valueLabel.color = [CCColor blackColor];
                        [self spellWord:tile.value];
                        [_word setString:[_word lowercaseString]];
                        CCLOG(@"%@", _word);
                    }
                }
            }
        }
    
        if (recognizer.state == UIGestureRecognizerStateChanged) {
    
        }
    
        if (recognizer.state == UIGestureRecognizerStateEnded) {
            for (Tile *tile in self.children) {
                if([tile isKindOfClass:[Tile class]]) {
    
                    CGRect tileBoundingBox = tile.boundingBox;
                    if (CGRectContainsPoint(tileBoundingBox, touchPoint)) {
                        tile.backgroundNode.color = [tile getColor:tile.value];
                        tile.valueLabel.color = [self getContrastColor:r green:g blue:b];
    
                    }
                }
            }
        }
    }
    
    // allow for simultaneous gestures
    - (BOOL)gestureRecognizer:(UIGestureRecognizer *) recognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
        return YES;
    }
    

1 个答案:

答案 0 :(得分:0)

回答你的问题:

  1. 这并没有让我感到需要一个子类UILongPressGestureRecognizer的编码情况。话虽如此,子类化通常是一种清理视图控制器代码的好方法,因此您不必在视图控制器类中拥有血腥手势识别器代码。但这里没有任何东西(据我理解)要求这样做。您通常会深入研究手势识别器的子类,您需要一些特殊的自定义行为(例如,如果某些复杂的标准失败,则手势会失败)。在我走这条路之前,我首先要看看你是否能用标准手势达到所需的用户体验。

  2. 我可以看到滑动手势互相干扰的唯一原因是您已指定shouldRecognizeSimultaneouslyWithGestureRecognizer应返回YES。这种情况用于需要多个识别器同时运行的情况,这在这里似乎没有必要(而且只是问题的根源)。

    我不清楚你是否真的想要一个单独的滑动手势,或者你是否只想要一个手势("长按和拖动")。但是,如果您需要单独的滑动手势,则通常会通过指定requireGestureRecognizerToFail来指定手势识别器的相对优先级(例如,为了能够识别滑动,需要长按以进行滑动以进行滑动)。但如果你真的只有一个手势("长按并拖动"),那么只需要一个手势识别器。

  3. 似乎没必要。如果要在识别出长按后检测到移动,可以在长按后移动"移动"您ifUIGestureRecognizedStateChanged的{​​{1}}语句中的代码,在长按被识别后,但在用户抬起手指之前发生。 onLongPress是一个连续的手势识别器,在手势最初被识别后,用户的手指会继续进行更新。


  4. 我知道你没有要求代码,但是如果你想要一个轻扫手势,以及一个长按手势,基本上是捡起它并拖动它的想法,你可以做类似的事情下列。注意,我做滑动手势需要长按才能失败,所以如果用户长按,则优先,否则会滑动。但是你可能根本不需要滑动手势,所以如果你不需要它,只需将它完全删除:

    UILongPressGestureRecognizer

    这可能不是您正在寻找的确切UI,但它说明了:

    1. 如何制作两个手势,其中一个需要另一个手势才能在手势之间建立优先级(如果你想要两个不同的手势,那么显然只是一个问题,你可能不会这样做)

    2. 没有#import <UIKit/UIGestureRecognizerSubclass.h> - (void)viewDidLoad { [super viewDidLoad]; UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; [self.view addGestureRecognizer:longPress]; // if you needed a second gesture, a swipe, completely distinct from the long press and drag // gesture, you could add it like so: // // UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)]; // [swipe requireGestureRecognizerToFail:longPress]; // // do additional swipe configuration // [self.view addGestureRecognizer:swipe]; } - (void)handleSwipe:(UISwipeGestureRecognizer *)gesture { // do your separate swipe stuff here } - (void)handleLongPress:(UILongPressGestureRecognizer *)gesture { static UIView *tileToMove; static CGPoint startCenter; static CGPoint startLocation; CGPoint location = [gesture locationInView:self.view]; switch (gesture.state) { case UIGestureRecognizerStateBegan: { // find the tile tileToMove = [self findTileToMove:location]; if (tileToMove) { // if found, capture state ... startCenter = tileToMove.center; startLocation = location; // ... and animate "pick up tile", so the user gets positive feedback // that the drag/swipe portion of the gesture is starting. [UIView animateWithDuration:0.25 animations:^{ tileToMove.transform = CGAffineTransformMakeScale(1.2, 1.2); }]; } else { gesture.state = UIGestureRecognizerStateFailed; } break; } case UIGestureRecognizerStateChanged: { // move the tile as the user's finger moves CGPoint translate = CGPointMake(location.x - startLocation.x, location.y - startLocation.y); // note, if you want to constrain the translation to be, for example, on the // x-axis alone, you could do something like: // // CGPoint translate = CGPointMake(location.x - startLocation.x, 0); tileToMove.center = CGPointMake(startCenter.x + translate.x, startCenter.y + translate.y); break; } case UIGestureRecognizerStateEnded: { // animate "drop the tile" [UIView animateWithDuration:0.25 animations:^{ tileToMove.transform = CGAffineTransformIdentity; // if you want the tile to "snap" to some location having let it go, // set the `center` or `frame` here. }]; // clear our variables, just in case tileToMove = nil; startCenter = CGPointZero; startLocation = CGPointZero; break; } default: break; } } - (UIView *)findTileToMove:(CGPoint)location { for (UIView *tile in self.tiles) { if (CGRectContainsPoint(tile.frame, location)) { return tile; } } return nil; } 方法,因为我不希望它们同时被识别。请注意,只有在您真正需要两个手势时才需要,您可能需要或不需要这两个手势;以及

    3. 如何进行长按,不仅可以识别初始长按,还可以识别后续的滑动/拖动动作。