I need to allow two-finger pinch/rotate/panning and deny single-finger panning.
I've tried some ways to achieve this:
for (UIPanGestureRecognizer *pan in mapView.gestureRecognizers) {
if ([pan isKindOfClass:[UIPanGestureRecognizer class]]) {
if ([pan minimumNumberOfTouches] < 2) {
[pan setMinimumNumberOfTouches:2];
}
}
}
But this not works. Maybe some kind of UIGestureRecognizer failing dependency?
Just found nice solution:
self.twoFingerPan = [[UIPanGestureRecognizer alloc] init];
self.twoFingerPan.maximumNumberOfTouches = 1;
self.twoFingerPan.delegate = self;
[self addGestureRecognizer:self.twoFingerPan];
...
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (gestureRecognizer == self.twoFingerPan &&
[otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] &&
(otherGestureRecognizer.view == self.mapView ||
otherGestureRecognizer.view.superview == self.mapView)) {
return YES;
}
return NO;
}
And addition to allow any outer scrolling:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (gestureRecognizer == self.twoFingerPan &&
[otherGestureRecognizer.view isKindOfClass:[UIScrollView class]]) {
return YES;
}
return NO;
}
Related
I want to enable keyboard shortcuts like Cmd+c , Cmd+v to work on webpages loaded inside WKWebView, but cannot find a solution.
Webview on the other hand has methods like Copy/Paste/Cut which could be leveraged by overriding (void)keyDown:(NSEvent *)event method. But WKWebView does not seem to have any similar funtion.
In WebView i could do something like
- (void)keyDown:(NSEvent *)event {
NSString *s = [event charactersIgnoringModifiers];
if (s == nil)
return;
if (([event modifierFlags] & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask)
{
if ([s caseInsensitiveCompare:#"a"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(selectAll:)])
[self.contentView selectAll:self];
}
else if ([s caseInsensitiveCompare:#"c"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(copy:)])
[self.contentView copy:self];
}
else if ([s caseInsensitiveCompare:#"v"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(paste:)])
[self.contentView paste:self];
}
else if ([s caseInsensitiveCompare:#"x"] == NSOrderedSame)
{
if ([[self firstResponder] respondsToSelector:#selector(cut:)])
[self.contentView cut:self];
}
else if ([s caseInsensitiveCompare:#"z"] == NSOrderedSame)
{
[self.contentView undo];
}
}
else
{
[super keyDown:event];
} }
In the above code self.contentView points to a WebView object
I have a very complicated problem with geolocation : the didupdatetolocation delegate method is not called which I'm not understand.
this the code of the method:
- (void) locationManager:(CLLocationManager *)pLocationManager didUpdateToLocation:(CLLocation *)pNewLocation fromLocation:(CLLocation *)pOldLocation {
lGPSAccuracy = 0;
// Stop trace record when the GPS Signal is poor or null
if (pNewLocation.horizontalAccuracy > GPS_POOR_SIGNAL || pNewLocation.horizontalAccuracy < 0){ return;}
if (pNewLocation.horizontalAccuracy > pNewLocation.verticalAccuracy) {
lGPSAccuracy = pNewLocation.horizontalAccuracy;
} else {
lGPSAccuracy = pNewLocation.verticalAccuracy;
}
if (self.delegate && [self.delegate respondsToSelector:#selector(traceRecorder:didUpdateToLocation:fromLocation:)]) {
[self.delegate traceRecorder:self didUpdateToLocation:pNewLocation fromLocation:pOldLocation];
}
CLLocationCoordinate2D lUserLocation = pNewLocation.coordinate;
Boolean lLatitudeOK = (self.mMapSouthWest.latitude < lUserLocation.latitude) && (lUserLocation.latitude < self.mMapNorthEast.latitude);
Boolean lLongitudeOK = (self.mMapSouthWest.longitude < lUserLocation.longitude) && (lUserLocation.longitude < self.mMapNorthEast.longitude);
//IF USER IS OUT OF THE MAP
if (self.delegate && [self.delegate respondsToSelector:#selector(userPositionOnMap:)]) {
if ( (!lLatitudeOK || !lLongitudeOK) ) {
[self.delegate userPositionOnMap:NO];
} else {
[self.delegate userPositionOnMap:YES];
}
}
if (![self isNewLocation:pNewLocation acceptableComparedToOldLocation:pOldLocation]) {
return;
}
[self treatLocation:pNewLocation];
}
when I read about this problem i found that this method is deprecated but it's still working on a old version of my project which is very abnormal.
Any help please.
Make sure your CLLocationManager variable isn't a local variable. And call startUpdatingLocation after creating CLLocationManager. One of these 2 mistake can make didUpdateToLocation isn't called.
Try my code below
- (void) beginMonitoring {
if (TracageAutomatic) {
tracageAutomaticTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(tracageAutomaticTimeCalled) userInfo:nil repeats:YES];
}
if (self.mLocationManager == nil) {
[self setMLocationManager: [[CLLocationManager alloc] init]];
[self.mLocationManager setDelegate:self];
[self.mLocationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[self.mLocationManager setDistanceFilter:2.0f]; //Minimum distance to move in meters before calling location update.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
//TODO: restore for iOS8
[self.mLocationManager requestWhenInUseAuthorization];
}
}
[self.mLocationManager startUpdatingLocation];
if ([self.mLocationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)]) {
[self.mLocationManager setAllowsBackgroundLocationUpdates:YES];
}
}
yes I'm sure that i did this in the code of this method which is called in running perfectly
- (void) beginMonitoring {
if (TracageAutomatic) {
tracageAutomaticTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(tracageAutomaticTimeCalled) userInfo:nil repeats:YES];
} else {
if (self.mLocationManager == nil) {
[self setMLocationManager: [[CLLocationManager alloc] init]];
[self.mLocationManager setDelegate:self];
[self.mLocationManager setDesiredAccuracy:kCLLocationAccuracyBestForNavigation];
[self.mLocationManager setDistanceFilter:2.0f]; //Minimum distance to move in meters before calling location update.
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
//TODO: restore for iOS8
[self.mLocationManager requestWhenInUseAuthorization];
}
}
[self.mLocationManager startUpdatingLocation];
if ([self.mLocationManager respondsToSelector:#selector(setAllowsBackgroundLocationUpdates:)]) {
[self.mLocationManager setAllowsBackgroundLocationUpdates:YES];
}
}
}
this the method to launch an automatic hike :
- (void) tracageAutomaticTimeCalled{
if (_mUserReachedTrackEnd){
[tracageAutomaticTimer invalidate];
tracageAutomaticTimer = nil;
}
[self treatLocation:[self.mTrackPoints objectAtIndex:tracageAutomaticCurrentIndex]];
tracageAutomaticCurrentIndex += TracageAutomoticPas;
if (tracageAutomaticCurrentIndex > [self.mTrackPoints count]){
tracageAutomaticCurrentIndex = (int)([self.mTrackPoints count]-1);
}
}
thank you #truncdug. I resolved the problem by changing the deprecated didtoupdatelocations method
- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
if ([locations count]>0) {
CLLocation *pNewLocation = [locations firstObject];
CLLocation *pOldLocation = _currentLocation;
_currentLocation = pNewLocation;
lGPSAccuracy = 0;
// Stop trace record when the GPS Signal is poor or null
if (pNewLocation.horizontalAccuracy > GPS_POOR_SIGNAL || pNewLocation.horizontalAccuracy < 0){ return;}
if (pNewLocation.horizontalAccuracy > pNewLocation.verticalAccuracy) {
lGPSAccuracy = pNewLocation.horizontalAccuracy;
} else {
lGPSAccuracy = pNewLocation.verticalAccuracy;
}
if (self.delegate && [self.delegate respondsToSelector:#selector(traceRecorder:didUpdateToLocation:fromLocation:)]) {
[self.delegate traceRecorder:self didUpdateToLocation:pNewLocation fromLocation:pOldLocation];
}
CLLocationCoordinate2D lUserLocation = pNewLocation.coordinate;
Boolean lLatitudeOK = (self.mMapSouthWest.latitude < lUserLocation.latitude) && (lUserLocation.latitude < self.mMapNorthEast.latitude);
Boolean lLongitudeOK = (self.mMapSouthWest.longitude < lUserLocation.longitude) && (lUserLocation.longitude < self.mMapNorthEast.longitude);
//IF USER IS OUT OF THE MAP
if (self.delegate && [self.delegate respondsToSelector:#selector(userPositionOnMap:)]) {
if ( (!lLatitudeOK || !lLongitudeOK) ) {
[self.delegate userPositionOnMap:NO];
} else {
[self.delegate userPositionOnMap:YES];
}
}
if (![self isNewLocation:pNewLocation acceptableComparedToOldLocation:pOldLocation]) {
return;
}
[self treatLocation:pNewLocation];
}
}
I'm trying to implement an async voice recording feature. There's a button that has a UILongPressGestureRecognizer and this starts the recording. Right now, when they let go, the recording is saved and sent.
#pragma mark - Actions
- (void) recordButtonPressed:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSGreyDotXLarge] forState:UIControlStateNormal];
[self startRecording];
}
if (gesture.state == UIGestureRecognizerStateEnded) {
[self stopRecording];
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSPinkDotXLarge] forState:UIControlStateNormal];
}
}
This works, but now I need to copy the now standard feature of allowing the user to drag their finger off the button while it's pressed to cancel the recording.
How to add a gestureRecognizer to tell if a user drags outside the control but is still pressing it?
I hope it will work for you....
BOOL cancelflag;
UIButton *recordBtn;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPress:)];
[longPress setDelegate:self];
[recordBtn addGestureRecognizer:longPress];
}
-(void)handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer
{
if(longPressRecognizer.state == UIGestureRecognizerStateBegan)
{
if (!stopBtnFlag)
{
if (!audioRecorder.recording)
{
[self performSelectorOnMainThread:#selector(setUpAudioRecorder) withObject:nil waitUntilDone:YES];
[audioRecorder record];
NSLog(#"Recording...");
}
stopBtnFlag = YES;
cancelflag =YES;
}
}
else if (longPressRecognizer.state == UIGestureRecognizerStateChanged)
{
[audioRecorder stop];
stopBtnFlag = NO;
NSLog(#"moved");
}
else if (longPressRecognizer.state == UIGestureRecognizerStateEnded)
{
if(cancelflag)
{
[audioRecorder stop];
[self playmusic];
}
}
}
#Jaleel's answer gave me a start. Here's a complete working version:
- (void) recordButtonPressed:(UILongPressGestureRecognizer *)gesture
{
if (gesture.state == UIGestureRecognizerStateBegan) {
[self.voiceRecorderView setCancelText:WSCancelLabelTextStart];
if (!audioRecorder.recording)
{
[self startRecording];
}
cancelflag = NO;
}
else if (gesture.state == UIGestureRecognizerStateChanged)
{
CGPoint touchPoint = [gesture locationInView:self.voiceRecorderView];
if (!CGRectContainsPoint(self.voiceRecorderView.recordButton.frame, touchPoint )) {
cancelflag = YES;
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSGreyDotXLarge] forState:UIControlStateNormal];
[self.voiceRecorderView setCancelText:WSCancelLabelTextCancelling];
}
else {
cancelflag = NO;
[self.voiceRecorderView.recordButton setImage:[UIImage imageNamed:kWSPinkDotXLarge] forState:UIControlStateNormal];
[self.voiceRecorderView setCancelText:WSCancelLabelTextStart];
}
}
else if (gesture.state == UIGestureRecognizerStateEnded) {
[self stopRecording];
if(!cancelflag)
{
[self sendRecording:self.recordingURL];
}
else {
[self.voiceRecorderView setCancelText:WSCancelLabelTextCancelled];
}
[self.voiceRecorderView resetView];
}
}
i had displayed some images in collectionview. now i want to select the image and press space button. If i pressed Space button , the image should quicklook in a seperate window. any idea?
On your view, do this:
- (void)keyDown:(NSEvent *)event
{
unichar firstChar = 0;
if ([[event charactersIgnoringModifiers] length] > 0)
firstChar = [[event charactersIgnoringModifiers] characterAtIndex:0];
if (firstChar == ' ')
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
else
{
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
[[NSApp mainWindow] makeKeyWindow];
}
}
else if (firstChar == NSRightArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectNextItem];
return;
}
}
else if (firstChar == NSLeftArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectPreviousItem];
return;
}
}
else
[super keyDown:event];
}
Then, I do this in my app's delegate (AppDelegate.m):
- (BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel
{
//note that this methods indeed gets called because NSApp's
//delegate is in the responder chain.
return YES;
}
- (void)beginPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = panel; //set an ivar
[panel setDataSource:self];
}
- (void)endPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = nil;
}
- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel
{
//return a number of your choice (depends on your own app)
}
- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel
previewItemAtIndex:(NSInteger)index
{
//return an object of your choice (depends on your app)
}
- (void)handleCurrentFileItemsSelectionChange:(NSNotification *)note
{
[previewPanel reloadData]; //referring to the ivar
}
i finally got. i just replaced imageViewes and put NSButton and setted spacebutton as keyequivalent as
- (BOOL)isOneOfMyKeyEquivs:(NSString *)keyChar
{
if (([keyChar isEqualToString:#" "])||([keyChar isEqualToString:#"\r"])) {
return YES;
} else {
return NO;
}
}
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
{
//NSLog(#"OK");
NSString* keyChar = [theEvent characters];
if ([self isOneOfMyKeyEquivs:keyChar])
{
[[self cell] setKeyEquivalent:keyChar];
}
return [super performKeyEquivalent:theEvent];
return NO;
}
and performed button action.
I want to stop bounce in webview. can my app get rejected in appstore if I use following statement in my code?
self.viewController.webView.scrollView.bounces = NO;
Thanks!
if ([[[UIDeice currentDevice] SystemVersion] floatValue] >= 5.0)//iOS>=5.0
{
webView.scrollView.bounces = NO;
}
else//iOS<5.0
{
for (id subview in webView.subviews)
{
if ([[subview class] isSubclassOfClass: [UIScrollView class]])
((UIScrollView *)subview).bounces = NO;
}
}
if (webView respondsToSelector:#selector(scrollView)]) {
webView.scrollView.bounces = NO;
} else {
for (id subview in webView.subviews) {
if ([[subview class] isSubclassOfClass:[UIScrollView class]]) {
((UIScrollView*)subview).bounces = NO;
}
}
}