Shake Detection iPhone 3.0 not working - iphone

I have a ViewController that works perfectly with a button that trigger an action. I would like to replace the button with a shake event so I've googled it around and created a ShakeDetector class that ineherits from UIView
and my implementation is as follow:
#implementation ShakeDetector
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (motion == UIEventSubtypeMotionShake )
{
// User was shaking the device. Post a notification named "shake".
//[[NSNotificationCenter defaultCenter] postNotificationName:#"spin" object:self];
NSLog(#"sss");
}
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
}
#end
But I can't make it work... any help?
Thanks

Put :
-(BOOL)canBecomeFirstResponder
{
return YES;
}
and for your view :
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
- (void)viewDidDisappear:(BOOL)animated {
[self resignFirstResponder];
[super viewDidDisappear:animated];
}
You can also write it in viewWillAppear and viewWillDisappear

Related

TouchesEnded not working in iOS5, working fine in iOS4

I have a custom scrollView with the following method implemented:
- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//if not dragging send it on up the chain
if(!self.dragging){
[self.nextResponder touchesEnded:touches withEvent:event];
}else {
[super touchesEnded:touches withEvent:event];
}
}
And in My View Controller I have the following method:
-(void) touchesEnded: (NSSet *) touches withEvent: (UIEvent *) event {
NSLog(#"TOUCH");
//---get all touches on the screen---
NSSet *allTouches = [event allTouches];
//---compare the number of touches on the screen---
switch ([allTouches count])
{
//---single touch---
case 1: {
//---get info of the touch---
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
//---compare the touches---
switch ([touch tapCount])
{
//---single tap---
case 1: {
NSLog(#"Single");
[self mySingleTapMethod];
} break;
//---double tap---
case 2: {
[self myDoubleTapMethod];
} break;
}
} break;
}
}
under iOS 4, this works perfectly, touches on the scrollview are recognized and the touchesEnded gets called in my view controller and all is right with the world. Under iOS 5x, however, the touchesEnded never gets fired. Does anyone know what the heck is going on/wrong?
Found the Answer here, basically if you want to do what I am doing you need to pass the touchesBegan up the chain as well.. because if a viewController didn't see the touchesBegan it won't get the TouchesEnded... So I modified the custom ScrollView to throw up the touchesBegan and everything now works fine in 5.0
Reference:
UIView touch handling behavior changed with Xcode 4.2?

How to intercept long press on UITextView without disabling context menu?

I want to intercept long press on UITextview, but don't want to disable the context menu option at the same time.
If I use gesture recognizer on textview, it will disable context menu so I am using the method like below now.
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
//fire my method here
}
But, it only fires the method when context menu shows up after the user long press some words. So when the user long press a blank space, then only the magnifying glass shows up, I can't fire the method at the time.
Does anyone have better ideas? Thanks!
//////The Problem Solved//////
Thanks to #danh and #Beppe, I made it even with tap gesture on UITextView. I wanted to show the font bar on textview by long press.
#First, I subclassed the UITextview.
#interface LisgoTextView : UITextView {
BOOL pressing_;
}
#property (nonatomic) BOOL pressing;
#end
#interface LisgoTextView (private)
- (void)longPress:(UIEvent *)event;
#end
#implementation LisgoTextView
#synthesize pressing = pressing_;
//--------------------------------------------------------------//
#pragma mark -- Long Press Detection --
//--------------------------------------------------------------//
- (void)longPress:(UIEvent *)event {
if (pressing_) {
//post notification to show font edit bar
NSNotification *fontEditBarNotification = [NSNotification notificationWithName:#"fontEditBarNotification"
object:nil userInfo:nil];
[[NSNotificationCenter defaultCenter] postNotification:fontEditBarNotification];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self performSelector:#selector(longPress:) withObject:event afterDelay:0.7];
pressing_ = YES;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
pressing_ = NO;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
pressing_ = NO;
}
#I used the delay to solve the conflict with tap gesture I implemented on UITextView.
- (void)tapGestureOnTextView:(UITapGestureRecognizer *)sender {
//cancel here if long press was fired first
if (cancelTapGesture_) {
return;
}
//don't fire show font bar
cancelShowFontBar_ = YES;
[self performSelector:#selector(enableShowFontBar) withObject:nil afterDelay:1.0];
//method here
}
- (void)showFontEditBar {
//cancel here if tap gesture was fired first
if (cancelShowFontBar_) {
return;
}
if (fontEditBarExists_ == NO) {
//method here
//don't fire tap gesture
cancelTapGesture_ = YES;
[self performSelector:#selector(enableTapGesture) withObject:nil afterDelay:1.0];
}
}
- (void)enableTapGesture {
cancelTapGesture_ = NO;
}
- (void)enableShowFontBar {
cancelShowFontBar_ = NO;
}
I usually avoid subclassing unless the docs explicitly suggest, this worked for me. Long press and context menu. Whoops - Answer just loaded by #Beppe. Great minds think alike :-)
#interface TextViewSubclass ()
#property(assign,nonatomic) BOOL pressing;
#end
#implementation TextViewSubclass
#synthesize pressing=_pressing;
- (void)longPress:(UIEvent *)event {
NSLog(#"long press");
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
self.pressing = YES;
[self performSelector:#selector(longPress:) withObject:event afterDelay:2.0];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[NSObject cancelPreviousPerformRequestsWithTarget:self];
self.pressing = NO;
}
#end
This worked for me. I just wanted to control what happens when the user taps or long presses a link
- (BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange
{
// check for long press event
BOOL isLongPress = YES;
for (UIGestureRecognizer *recognizer in self.commentTextView.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]){
if (recognizer.state == UIGestureRecognizerStateFailed) {
isLongPress = NO;
}
}
}
if (isLongPress) {
// user long pressed a link, do something
} else {
// user tapped on a link, do something
}
// return NO cause you dont want the normal behavior to occur
return NO;
}
Adaptation of Lucas Chwe's answer to work on iOS 9 (and 8). See comment in his answer.
The gist: invert the logic by starting with "no long press", then switch to "long press detected" if at least one UILongPressGestureRecognizer is in Began state.
BOOL isLongPress = NO;
for (UIGestureRecognizer *recognizer in textView.gestureRecognizers) {
if ([recognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
if (recognizer.state == UIGestureRecognizerStateBegan) {
isLongPress = YES;
}
}
}
Still a bit hackish, but working for iOS 8 and 9 now.
This is a little tricky, but it works for me.
I add a subclass of UIButton on top of my UITextView, check for long touches and pass them to UITextView this way:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
isLongTouchDetected = NO;
[self performSelector:#selector(longTouchDetected) withObject:nil afterDelay:1.0];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
if (isLongTouchDetected == YES) {
[super touchesCancelled:touches withEvent:event];
} else {
[super touchesEnded:touches withEvent:event];
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(longTouchDetected) object:nil];
}
}
- (void)longTouchDetected {
isLongTouchDetected = YES;
// pass long touch to UITextView
}
For SWIFT [Easiest Way]
extension UITextField {
override public func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
if action == "paste:" {
return false
}
return super.canPerformAction(action, withSender: sender)
}
override public func addGestureRecognizer(gestureRecognizer: UIGestureRecognizer) {
if gestureRecognizer.isKindOfClass(UILongPressGestureRecognizer) {
gestureRecognizer.enabled = false
}
super.addGestureRecognizer(gestureRecognizer)
return
}
}
Above code has also function for disable "PASTE" option in content menu.
Could you use the textViewDidChangeSelection method of the UITextViewDelegate protocol?

Can't get shake events on iPhone

I am not being able to get shake events on iPhone.
I have followed other questions here with no result. I also tried following the GLPaint example from Apple, but it seems exactly like my source code, with a small diference. GLPaint's source code /works/, mine /doesn't/.
So, here it is what I have:
Controller.m
- (void)awakeFromNib {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(shakeEnded) name:#"shake" object:nil];
}
ShakingEnabledWindow.m
- (void)shakeEnded {
NSLog(#"Shaking ended.");
}
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
}
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake ) {
// User was shaking the device. Post a notification named "shake".
[[NSNotificationCenter defaultCenter] postNotificationName:#"shake" object:self];
NSLog(#"Shaken!");
}
}
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event {
}
My XIB has a window, which is a ShakingEnabledWindow and an object, my Controller.
I am running out of ideas here, hope someone can give me a hand. :)
Documentation of NSNotificationCenter says:
addObserver:selector:name:object:
notificationSelector Selector that
specifies the message the receiver
sends notificationObserver to notify
it of the notification posting. The
method specified by
notificationSelector must have one and
only one argument (an instance of
NSNotification).
So your shakeEnded method is wrong as it takes no parameters. It should look:
- (void)shakeEnded:(NSNotification*)notiication {
NSLog(#"Shaking ended.");
}
- (void)awakeFromNib {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(shakeEnded:) name:#"shake" object:nil];
}
In viewDidAppear, become the first responder:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
And make sure you can be first responder:
- (BOOL)canBecomeFirstResponder {
return YES;
}
Then you can implement the motion detection.
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (event.subtype == UIEventTypeMotion){
//there was motion
}
}
I think you are incorrectly checking the motion type. You need to check against event.subtype instead of motion:
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if ( event.subtype == UIEventSubtypeMotionShake ) {
// Put in code here to handle shake
}
}

Why is my application not detecting a shake gesture?

I'm trying to enable shake gestures within my application but I'm having a problem.
I have different view controllers, but on one of them (not the main view controller for the application) nothing happens in response to a shake gesture. What could be the problem?
The relevant code is as follows:
-(BOOL)canBecomeFirstResponder {
return YES;
}
-(void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self becomeFirstResponder];
}
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
{
if (event.subtype == UIEventSubtypeMotionShake)
{
NSLog (#"SHAKED");
}
}
I think you should be checking motion, not event. Like this:
-(void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event {
if (motion == UIEventSubtypeMotionShake ) {
NSLog(#"SHOOK");
}
}

A problem with override UINavigationController

now i'm working with cocos2d and i design to add navigationcontroller to my cocos2d application,
so i add navigationcontroller to my application when i click it not pass touch or event to cocos2d
now i'm try to override UINavigationController by
add new new class name is NavigationController and inherit from UINavigationController
in init i call [super init];
every things look be ok
but when i try to add
- (BOOL)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Im overriding touch");
return YES;
}
- (BOOL)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"Im overriding touchMove");
return YES;
}
it not call
Why are you calling the methods ccTouchesBegan:withEvent: and ccTouchesMoved:withEvent: instead of the original names? You don't have to change the names of the methods when you subclass UINavigationController; instead, you should keep the same names and call super on them as well as appropriate. For example:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"I'm overriding touch");
[super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
NSLog(#"I'm overriding move");
[super touchesMoved:touches withEvent:event];
}