ios - Using a Long Press Gesture only if certain conditions are met -
i trying create long press gesture presents second view controller, once press has been held 3 seconds. however, want second view controller presented if device in accelerometer orientation entire 3 seconds. is, if gesture not held long enough or device tilted much, gesture dismissed , user must try again.
// in firstviewcontroller.h
#import <uikit/uikit.h> #import <coremotion/coremotion.h> @interface firstviewcontroller : uiviewcontroller @property (nonatomic, strong) cmmotionmanager *motionmanager; @end
// in firstviewcontroller.m
#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 here }
i have tried chunks of code in last method looks obnoxious , not correct. instead, have listed several lines of code below know work individually, need assistance in making them work together.
// accelerometer
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 flat , screen faces { nslog(@"correct orientation!!!"); [self.motionmanager stopaccelerometerupdates]; } else { nslog(@"incorrect orientation!!!"); [self.motionmanager stopaccelerometerupdates]; }]; } else { nslog(@"accelerometer not available."); }
// go second view controller
if (sender.state == uigesturerecognizerstatebegan) { secondviewcontroller *svc = [self.storyboard instantiateviewcontrollerwithidentifier:@"secondviewcontroller"]; [self presentviewcontroller:svc animated:yes completion:nil]; }
any ideas? or more general way cancel gesture unless condition met helpful.
i hope code verbose enough read, it's pretty self explanatory - i've stuck accelerometer code, , used same variable names.
#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 resources can 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 flat , screen faces { 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 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 current times, interval since touches timestamp refers system boot // more feasible use boot time, simplicity, i'm using 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 -(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
Comments
Post a Comment