簡體   English   中英

長按后滑動

[英]Swipe after long press

好的,我正在幫助將Android游戲轉換為iOS。 該游戲基於2048年,但使用字母而不是數字。 我有一點工作但仍在學習Objective C / iOS怪癖。 到目前為止,我有瓷磚/網格工作,運動工作等,但我需要一點幫助。 目標是允許用戶長按瓷磚以選擇它,然后將他們的手指滑動到相鄰的瓷磚以開始拼寫單詞。 我已經實施了長按部分但是我對如何讓它長按然后滑動有點不知所措。 除此之外,我已經有一個滑動,允許用戶移動瓷磚。 在這里搜索我已經看到有關子類化的建議,所以我想要我需要子類化UISwipeGestureRecognizer方法。 我已經放入了同時手勢識別器,但我不確定從哪里開始。

所以,這有幾個問題。

  1. 最好的方法是什么? 實現每個UISwipeGestureRecognizer的子類?

  2. 我當前的滑動檢測是否會干擾? (此時滑動本身會在滑動方向上移動切片)

  3. 我猜我需要做一個(如果長按)然后激活子類滑動方法?

  4. 回答上述問題的任何例子都會有很大的幫助。 我不是要求你為我做這件事,但至少要指出我的方向。 謝謝!

代碼如下。

//  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. 這不會讓我感到需要一個子類UILongPressGestureRecognizer的編碼情況。 話雖如此,子類化通常是清理一個視圖控制器代碼的好方法,因此您在視圖控制器類中沒有血腥手勢識別器代碼。 但這里沒有任何東西(據我理解)要求。 您通常會深入研究手勢識別器的子類,您需要一些特殊的自定義行為(例如,如果某些復雜的標准失敗,則手勢會失敗)。 不過,在我走這條路之前,我首先要看看你是否可以通過標准手勢實現所需的用戶體驗。

  2. 我可以看到滑動手勢互相干擾的唯一原因是你已經指定shouldRecognizeSimultaneouslyWithGestureRecognizer應該返回YES 這用於需要多個識別器同時運行的情況,這在這里似乎沒有必要(並且只是問題的根源)。

    我不清楚你是否真的想要一個單獨的滑動手勢或者你是否只想要一個手勢(“長按並拖動”)。 但是,如果您需要單獨的滑動手勢,則通常會通過指定requireGestureRecognizerToFail來指定手勢識別器的相對優先級(例如,滑動需要長按才能失敗以便識別滑動)。 但如果你真的只有一個手勢(“長按並拖動”),那么只需要一個手勢識別器。

  3. 這似乎沒必要。 如果要在識別長按后檢測移動,可以在onLongPress UIGestureRecognizedStateChangedif語句中設置“長按后移動”代碼,這在長按被識別后但在用戶抬起之前發生他們的手指。 UILongPressGestureRecognizer是一個連續的手勢識別器,在手勢最初被識別后,當用戶的手指移動時,它將繼續獲得更新。


我知道你沒有要求代碼,但是如果你想要一個輕掃手勢,以及一個長按手勢,基本上是拾取它並拖動它的想法,你可以做類似下面的事情。 注意,我做滑動手勢需要長按才能失敗,所以如果用戶長按,則優先,否則會滑動。 但是你可能根本不需要滑動手勢,所以如果你不需要它,只需將它完全刪除:

#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;
}

這可能不是您正在尋找的確切UI,但它說明了:

  1. 如何使用兩個手勢,其中一個手勢需要另一個手勢才能在手勢之間建立優先級(如果你想要兩個不同的手勢,那么很明顯只是一個問題,你可能不會這樣做);

  2. 沒有shouldRecognizeSimultaneouslyWithGestureRecognizer方法,因為我不希望它們同時被識別。 請注意,只有在您真正需要兩個手勢時才需要,您可能需要或不需要這兩個手勢;

  3. 如何進行長按,不僅可以識別初始長按,還可以識別后續的滑動/拖動動作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM