首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >只有在满足某些条件的情况下才使用长按压手势

只有在满足某些条件的情况下才使用长按压手势
EN

Stack Overflow用户
提问于 2013-07-31 18:56:42
回答 3查看 355关注 0票数 0

我试图创建一个长的新闻姿态,以显示第二个视图控制器,一旦媒体已经举行了3秒。然而,我只想要第二个视图控制器,如果设备是在一个特定的加速度计的方向,在整个3秒。也就是说,如果手势保持的时间不够长或设备倾斜过大,则该手势将被拒绝,用户必须再次尝试。

//在FirstViewController.h中

代码语言:javascript
运行
复制
#import <UIKit/UIKit.h>
#import <CoreMotion/CoreMotion.h>

@interface FirstViewController : UIViewController

@property (nonatomic, strong) CMMotionManager *motionManager;

@end

//在FirstViewController.m中

代码语言:javascript
运行
复制
#import "FirstViewController"
#import "SecondViewController"

@implementation motionManager;

- (void) viewDidLoad
{
    [super viewDidLoad];
    self.motionManager = [[CMMotionManager alloc]init];
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc]initWithTarget:self action:@selector(handleLongPress:)];
    longPress.minimumPressDuration = 3.0;
    [self.view addGestureRecognizer:longPress];
}

- (void) handleLongPress: (UILongPressGestureRecognizer *)sender
{
    // Not sure what to do here
}

我以前在最后一个方法中尝试过一些代码块,但是它看起来很讨厌,只是不正确。相反,我在下面列出了几行代码,我知道这些代码是单独工作的,但我需要帮助使它们一起工作。

//加速度计

代码语言:javascript
运行
复制
if ([self.motionManager isAccelerometerAvailable])
{
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [self.motionManager startAccelerometerUpdatesToQueue:queue withHandler:^(CMAccelerometerData *accelerometerData,NSError *error)
    {
        if (ABS(accelerometerData.acceleration.x) < 0.3 && ABS(accelerometerData.acceleration.y) < 0.30 && ABS(accelerometerData.acceleration.z) > 0.70) // Phone is flat and screen faces up
        { 
            NSLog(@"Correct Orientation!!!");
            [self.motionManager stopAccelerometerUpdates];
        }
        else
        {
            NSLog(@"Incorrect orientation!!!");
            [self.motionManager stopAccelerometerUpdates];
        }];
}

else
{
    NSLog(@"Accelerometer is not available.");
}

//转到第二视图控制器

代码语言:javascript
运行
复制
if (sender.state == UIGestureRecognizerStateBegan)
{
    SecondViewController *svc = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
    [self presentViewController:svc animated:YES completion:nil];
}

有什么想法吗?或者更一般的方式取消手势,除非条件得到满足,这将是非常有帮助的。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-08-01 18:04:58

我希望这段代码足够详细,足以让您阅读,这是非常不言自明的--我一直在使用您的加速度计代码,并且使用了相同的变量名。

代码语言:javascript
运行
复制
#import "ViewController.h"
#import <CoreMotion/CoreMotion.h>

@interface ViewController () {

    NSOperationQueue    *motionQueue;
    NSTimer             *touchTimer;
    NSTimeInterval      initialTimeStamp;
    BOOL                touchValid;

    float                timerPollInSeconds;
    float                longPressTimeRequired;
}

@property (strong, nonatomic)            NSTimer             *touchTimer;
@property (assign, nonatomic)            NSTimeInterval      initialTimeStamp;
@property (assign, nonatomic)            BOOL                touchValid;
@property (assign, nonatomic)            float               timerPollInSeconds;
@property (assign, nonatomic)            float               longPressTimeRequired;
@property (strong, nonatomic)            CMMotionManager     *motionManager;
@property (strong, nonatomic)            NSOperationQueue    *motionQueue;


@end

@implementation ViewController

@synthesize touchTimer = _touchTimer, initialTimeStamp, touchValid, motionQueue = _motionQueue;
@synthesize timerPollInSeconds, longPressTimeRequired, motionManager = _motionManager;

- (void)viewDidLoad
{
    self.timerPollInSeconds = 0.25f;
    self.longPressTimeRequired = 3.0f;
    self.touchTimer = nil;
    self.touchValid = NO;
    self.initialTimeStamp = NSTimeIntervalSince1970;
    self.motionManager = [[CMMotionManager alloc] init];
    self.motionQueue = [[NSOperationQueue alloc] init];
    [_motionQueue setName:@"MotionQueue"];
    [_motionQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount];

    [super viewDidLoad];

    self.view.multipleTouchEnabled = NO;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma mark - Operations

-(void) startLongPressMonitorWithTimeStamp:(NSTimeInterval) timeStamp {
    NSLog(@"Starting monitoring - %g", timeStamp);
    if( self.touchTimer ) {
        if( [_touchTimer isValid] ) {
            [_touchTimer invalidate];
        }
    }

    self.touchTimer = [NSTimer timerWithTimeInterval:self.timerPollInSeconds target:self selector:@selector(timerPolled:) userInfo:nil repeats:YES];

    if( [_motionManager isAccelerometerAvailable] ) {
        NSLog(@"Accelerometer Available");
        if( ![_motionManager isAccelerometerActive] ) {
            NSLog(@"Starting Accelerometer");
            [_motionManager startAccelerometerUpdatesToQueue:self.motionQueue withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {

                if (ABS(accelerometerData.acceleration.x) < 0.3 && ABS(accelerometerData.acceleration.y) < 0.30 && ABS(accelerometerData.acceleration.z) > 0.70) // Phone is flat and screen faces up
                {
                    dispatch_sync(dispatch_get_main_queue(), ^{
                        self.touchValid = YES;
                    });
                }
                else
                {
                    dispatch_sync(dispatch_get_main_queue(), ^{
                        self.touchValid = NO;
                        [self stopLongPressMonitoring:YES];
                    });
                };
            }];
        }
        else {
            NSLog(@"Accelerometer already active");
        }
    }
    else {
        NSLog(@"Accelerometer not available");
    }

    self.initialTimeStamp = timeStamp;

    self.touchValid = YES;
    [_touchTimer fire];

    [[NSRunLoop mainRunLoop] addTimer:self.touchTimer forMode:NSRunLoopCommonModes];
}



-(void) stopLongPressMonitoring:(BOOL) touchSuccessful {
    [_motionManager stopAccelerometerUpdates];
    [_touchTimer invalidate];
    self.touchValid = NO;

    if( touchSuccessful ) {
        NSLog(@"Yes");
    }
    else {
         NSLog(@"No");
    }
}

#pragma mark - User Interaction
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

    //We're using the current times, interval since the touches timestamp refers to system boot up
    // it is more than feasible to use this boot up time, but for simplicity, I'm just using this
    NSTimeInterval timestamp = [NSDate timeIntervalSinceReferenceDate];
    [self startLongPressMonitorWithTimeStamp:timestamp];
}

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if( self.touchValid && [NSDate timeIntervalSinceReferenceDate] - self.initialTimeStamp == self.longPressTimeRequired ) {
        [self stopLongPressMonitoring:YES];
    }
    else {
        [self stopLongPressMonitoring:NO];
    }
}



#pragma mark - Timer Call back
-(void) timerPolled:(NSTimer *) timer {
    NSTimeInterval firedTimeStamp = [NSDate timeIntervalSinceReferenceDate];
    NSLog(@"Timer polled - %g", firedTimeStamp);
    if( self.touchValid ) {
        NSLog(@"Time elapsed: %d", (int)(firedTimeStamp - self.initialTimeStamp));

        if( firedTimeStamp - self.initialTimeStamp >= self.longPressTimeRequired ) {
            NSLog(@"Required time has elapsed");
            [self stopLongPressMonitoring:YES];
        }
    }
    else {
        NSLog(@"Touch invalidated");
        [self stopLongPressMonitoring:NO];
    }
}


@end
票数 0
EN

Stack Overflow用户

发布于 2013-07-31 20:03:35

您可以通过subclassing UIGestureRecognizer来做您想做的事情,使您自己的手势识别器类似于UILongPressGestureRecognizer,除了按下至少3秒的持续时间外,还可以监听加速度计的数据。

票数 0
EN

Stack Overflow用户

发布于 2013-07-31 20:08:21

我可能会重写onTouchesBegan和onTouchesEnded方法,而不是使用手势识别器。

然后在视图控制器中创建一个NSTimer对象、一个NSTimeInterval变量和一个BOOL;为此,我将调用它们,touchTimer、initialTouchTimeStamp和touchValid。

考虑到复杂性,它假设viewControllers视图不是多点触摸。

假设repeatTime =0.25f,longPressTimeRequired = 3;

计时器选择器将合并您的加速度计方法,如果您的加速度计方法中的数据无效,我会将touchValid设置为false (并使计时器失效),否则,在检查加速度计之后,我会将其设置为true,如果是,则检查initialTouchTimeStamp var是否为longPressTimeRequired或[touchTimer fireDate] - repeatTime之前的更多秒,如果为真,则将转到第二个控制器。

onTouchesBegan,我将使touchTimer失效,并创建一个新的touchTimer,它将每隔repearTime秒重复一次,并持续y秒。将touchValid设置为NO,将initialTouchTimeStamp设置为touch.timestamp。

onTouchesEnded,我将使touchTimer失效,并检查我的initialTouchTimeStamp变量是否是[touchTimer fireDate] - repeatTime之前的longPressTimeRequired或更多秒,如果是,并且touchValid是真的,那么我将转到我的第二个控制器。

这里有许多共同的元素,它可能不是最优雅的做事方式,但它应该能工作。希望这能有所帮助。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/17978611

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档