[英]Swipe after long press
好的,我正在帮助将Android游戏转换为iOS。 该游戏基于2048年,但使用字母而不是数字。 我有一点工作但仍在学习Objective C / iOS怪癖。 到目前为止,我有瓷砖/网格工作,运动工作等,但我需要一点帮助。 目标是允许用户长按瓷砖以选择它,然后将他们的手指滑动到相邻的瓷砖以开始拼写单词。 我已经实施了长按部分但是我对如何让它长按然后滑动有点不知所措。 除此之外,我已经有一个滑动,允许用户移动瓷砖。 在这里搜索我已经看到有关子类化的建议,所以我想要我需要子类化UISwipeGestureRecognizer
方法。 我已经放入了同时手势识别器,但我不确定从哪里开始。
所以,这有几个问题。
最好的方法是什么? 实现每个UISwipeGestureRecognizer
的子类?
我当前的滑动检测是否会干扰? (此时滑动本身会在滑动方向上移动切片)
我猜我需要做一个(如果长按)然后激活子类滑动方法?
回答上述问题的任何例子都会有很大的帮助。 我不是要求你为我做这件事,但至少要指出我的方向。 谢谢!
代码如下。
// 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;
}
在回答你的问题时:
这不会让我感到需要一个子类UILongPressGestureRecognizer
的编码情况。 话虽如此,子类化通常是清理一个视图控制器代码的好方法,因此您在视图控制器类中没有血腥手势识别器代码。 但这里没有任何东西(据我理解)要求。 您通常会深入研究手势识别器的子类,您需要一些特殊的自定义行为(例如,如果某些复杂的标准失败,则手势会失败)。 不过,在我走这条路之前,我首先要看看你是否可以通过标准手势实现所需的用户体验。
我可以看到滑动手势互相干扰的唯一原因是你已经指定shouldRecognizeSimultaneouslyWithGestureRecognizer
应该返回YES
。 这用于需要多个识别器同时运行的情况,这在这里似乎没有必要(并且只是问题的根源)。
我不清楚你是否真的想要一个单独的滑动手势或者你是否只想要一个手势(“长按并拖动”)。 但是,如果您需要单独的滑动手势,则通常会通过指定requireGestureRecognizerToFail
来指定手势识别器的相对优先级(例如,滑动需要长按才能失败以便识别滑动)。 但如果你真的只有一个手势(“长按并拖动”),那么只需要一个手势识别器。
这似乎没必要。 如果要在识别长按后检测移动,可以在onLongPress
UIGestureRecognizedStateChanged
的if
语句中设置“长按后移动”代码,这在长按被识别后但在用户抬起之前发生他们的手指。 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,但它说明了:
如何使用两个手势,其中一个手势需要另一个手势才能在手势之间建立优先级(如果你想要两个不同的手势,那么很明显只是一个问题,你可能不会这样做);
没有shouldRecognizeSimultaneouslyWithGestureRecognizer
方法,因为我不希望它们同时被识别。 请注意,只有在您真正需要两个手势时才需要,您可能需要或不需要这两个手势; 和
如何进行长按,不仅可以识别初始长按,还可以识别后续的滑动/拖动动作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.