I've setup a tap gesture recognizer and add the recognizer to the uibutton. The button has a background image. When I tap the button it doesn't highlight at all, the only thing I've been able to get it to do is change it's alpha value.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(singleTapGestureCaptured:)];
singleTap.cancelsTouchesInView = NO;
[btnNext addGestureRecognizer:singleTap];
- (void)singleTapGestureCaptured:(UITapGestureRecognizer *)gesture
{
UIView *tappedView = [gesture.view hitTest:[gesture locationInView:gesture.view] withEvent:nil];
NSLog(#"Touch event view: %#",[tappedView class]);
UIButton *myButton = (UIButton *) tappedView;
[self highlightButton:myButton];
tappedView.alpha = 0.5f;
}
Any would be appreciated. Thanks
You can intercept the touches events with a gesture recognizer, and then programmatically add the recognizer to all your uibuttons. For instance:
//
// HighlighterGestureRecognizer.h
// Copyright 2011 PathwaySP. All rights reserved.
//
#import <Foundation/Foundation.h>
#interface HighlightGestureRecognizer : UIGestureRecognizer {
id *beganButton;
}
#property(nonatomic, assign) id *beganButton;
#end
and the implementation:
//
// HighlightGestureRecognizer.m
// Copyright 2011 PathwaySP. All rights reserved.
//
#import "HighlightGestureRecognizer.h"
#implementation HighlightGestureRecognizer
#synthesize beganButton;
-(id) init{
if (self = [super init])
{
self.cancelsTouchesInView = NO;
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
self.beganButton = [[[event allTouches] anyObject] view];
if ([beganButton isKindOfClass: [UIButton class]]) {
[beganButton setBackgroundImage:[UIImage imageNamed:#"grey_screen"] forState:UIControlStateNormal];
[self performSelector:#selector(resetImage) withObject:nil afterDelay:0.2];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
}
- (void)reset
{
}
- (void)ignoreTouch:(UITouch *)touch forEvent:(UIEvent *)event
{
}
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer
{
return NO;
}
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
{
return NO;
}
- (void)resetImage
{
[beganButton setBackgroundImage: nil forState:UIControlStateNormal];
}
#end
The way you'd add the gesture recognizer to your button would be like so:
HighlighterGestureRecognizer * tapHighlighter = [[HighlighterGestureRecognizer alloc] init];
[myButton addGestureRecognizer:tapHighlighter];
[tapHighlighter release];
So basically you're declaring it, initializing it, and then adding it. After that, you'll want to release it, since the addGestureRecognizer retains it.
Also simply try
adjustsImageWhenHighlighted = YES set on your buttons? The default is YES, but maybe you changed it in the xib. It's the "Highlighted Adjusts Image" checkbox in the attributes inspector:
Related
I have found tutorial which I want to implement in my view controller but the code is written in UIView so how to convert UIView code into UIViewController it can work here is my code
#import <UIKit/UIKit.h>
#interface MyLineDrawingView : UIView {
UIBezierPath *myPath;
UIColor *brushPattern;
}
#end
#import "MyLineDrawingView.h"
#implementation MyLineDrawingView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.backgroundColor=[UIColor whiteColor];
myPath=[[UIBezierPath alloc]init];
myPath.lineCapStyle=kCGLineCapRound;
myPath.miterLimit=0;
myPath.lineWidth=10;
brushPattern=[UIColor redColor];
}
return self;
}
Only override drawRect: if you perform custom drawing.
An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
[brushPattern setStroke];
[myPath strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
// Drawing code
//[myPath stroke];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath moveToPoint:[mytouch locationInView:self]];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *mytouch=[[touches allObjects] objectAtIndex:0];
[myPath addLineToPoint:[mytouch locationInView:self]];
[self setNeedsDisplay];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//handle touch event
}
Create a UIViewController Object and set the view property to this view. Something like this should work.
UIViewController *vc = [[UIViewController alloc] init];
MyLineDrawingView *myView = [[MyLineDrawingView alloc] init];
vc.view = myView;
I'm actually trying to insert touch delegate functions (type touchBegan:withEvent, or touchEnded:withEvent) inside a customScrollView class that implement gestureRecognizers.
When I try to set the delegate of the recognizer object to self, my SDK has a message of warning stating "incompatible type id ".
I understand that the delegate protocol of GestureRecognizer does not include such function, but I don't know which delegate I should trigger in order to use the aforesaid function inside my custom view.
Thank you very much for your responses
Victor-Marie
Here is my code:
#interface TapScrollView : UIScrollView {
// id<TapScrollViewDelegate> delegate;
NSMutableArray *classementBoutons;
int n;
int o;
//UIImageView *bouton;
}
//#property (nonatomic, assign) id<TapScrollViewDelegate> delegate;
//#property (nonatomic, retain) UIImageView *bouton;
//#property (strong, nonatomic) UIPanGestureRecognizer *bouton01pan;
-(id)init;
-(void)initierScrollView;
-(void) createGestureRecognizers;
-(IBAction)handlePanGesture:(UIPanGestureRecognizer*)sender;
#end
#import "TapScrollView.h"
#implementation TapScrollView
//#synthesize bouton;
- (void)setUpBoutonView {
// Create the placard view -- its init method calculates its frame based on its image
//boutonHome *aBoutonMain = [[boutonHome alloc] init];
//self.boutonMain = aBoutonMain;
//[boutonMain setCenter:CGPointMake(200, 200)];
//[self addSubview:boutonMain];
}
- (id) init
{
if (self = [super init])
{
NSLog(#"Classe TapScrollView initiƩe");
}
return self;
}
-(void)initierScrollView
{
int i;
for (i=0; i<6; i++) {
UIImage *image = [UIImage imageNamed:#"back.png"];
UIImageView *bouton = [[UIImageView alloc] initWithImage:image];
[bouton setTag:i];
[bouton setFrame:CGRectMake(72+20*i,10,62,55)];
[classementBoutons insertObject:bouton atIndex:i];
bouton.userInteractionEnabled = YES;
UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanGesture:)];
recognizer.delegate = self;
[bouton addGestureRecognizer:recognizer];
[self addSubview:bouton];
}
}
//- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
//{
// UITouch *touch = [touches anyObject];
//[super touchesBegan:touches withEvent:event];
// for (o=1; o<6; o++) {
// if ([touch view] == [self viewWithTag:o])
// {
// UIPanGestureRecognizer *recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:[classementBoutons objectAtIndex:o] action:#selector(handlePanGesture:)];
// [[classementBoutons objectAtIndex:o] addGestureRecognizer:recognizer];
// bouton01 = [self viewWithTag:o];
// }
// }
//CGPoint touchPoint = [touch locationInView:self];
//[self animateFirstTouchAtPoint:touchPoint];
// return;
//}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
for (n=0; n<6; n++) {
NSLog(#"touche cancelled");
[[classementBoutons objectAtIndex:n] setFrame:CGRectMake((72+20)*n,10,62,55)];
}
}
//- (id<TapScrollViewDelegate>) delegate {
// return (id<TapScrollViewDelegate>)super.delegate;
//}
//- (void) setDelegate:(id<TapScrollViewDelegate>) aDelegate
//{
// super.delegate = aDelegate;
//}
#define GROW_ANIMATION_DURATION_SECONDS 0.15
#define SHRINK_ANIMATION_DURATION_SECONDS 0.15
-(IBAction)handlePanGesture:(UIPanGestureRecognizer*)recognizer
{
NSLog(#"Mouvement ok");
CGPoint translation = [recognizer translationInView:self];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self];
}
#end
Try specifying:
#interface TapScrollView : UIScrollView <UIGestureRecognizerDelegate> {
In this way, your warning should disappear, although I have to admit I have not entirely clear what you are trying to accomplish, so there might be other problems.
I have applied gesture on whole view and I want to interact with table view within self.view.I have applied custom gesture.that is as follows:
#import "TouchEvent.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
#implementation TouchEvent
#synthesize xInc=_inc;
#synthesize prev=_prev;
#synthesize diff=_diff;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setState:UIGestureRecognizerStateBegan];
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setState:UIGestureRecognizerStateCancelled];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
// A tap can have slight movement, but we're not interested
// in a tap. We want more movement. So if a tap is detected
// fail the recognizer.
if ([self state] == UIGestureRecognizerStatePossible) {
[self setState:UIGestureRecognizerStateBegan];
} else {
[self setState:UIGestureRecognizerStateChanged];
}
UIView *view = [self view];
CGPoint touchpoint = [touch locationInView:view];
CGPoint prevPoint=[touch previousLocationInView:view];
if (prevPoint.x<touchpoint.x)
[self setDiff:(touchpoint.x-prevPoint.x)];
else
[self setDiff:(prevPoint.x-touchpoint.x)];
NSLog(#"difference is: %f",self.diff);
NSLog(#"x is: %f",touchpoint.x);
[self setXInc:touchpoint.x];
[self setPrev:prevPoint.x];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self setState:UIGestureRecognizerStateEnded];
}
#end
and I m applying like this
- (void)viewDidLoad
{
NSArray *ary=[NSArray arrayWithObjects:#"Friends",#"Message",#"Chats",#"New Feeds",#"Photos",#"Notes", nil];
array=ary;
gestur=[[TouchEvent alloc] initWithTarget:self action:#selector(SLideTheView:)];
[self.view addGestureRecognizer:gestur];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)moveIt:(CGFloat)x_pos
{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[viewU setFrame:CGRectMake(x_pos, 0, 320, 460)];
[UIView commitAnimations];
}
-(void)SLideTheView:(TouchEvent*)gesture
{
CGPoint pt=[gesture locationInView:viewU];
if (pt.x>13&&pt.y>5&&pt.x<29&&pt.y<23)
{
[self slideView];
}
else
{
if (gesture.state==UIGestureRecognizerStateEnded)
{
if (viewU.frame.origin.x!=0) {
if (gesture.prev<gesture.xInc)
{
[self moveIt:270];
}
else
[self moveIt:0];
}
}
else
{
if (viewU.frame.origin.x!=0)
{
if (gesture.prev<gesture.xInc)
x=viewU.frame.origin.x+gesture.diff;
else
x=viewU.frame.origin.x-gesture.diff;
[viewU setFrame:CGRectMake(x, 0, 320, 460)];
}
}
}
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
label.text=[array objectAtIndex:[indexPath row]];
[self slideView];
}
the running image is as follows:
you can use requireGestureRecognizerToFail: to able to recognize two or more gesture recognizers on same view see example code here
edit
so you can refer this one
the method to be referenced is - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
refer this question for more
//add gesture to mapview-for single touch
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(SLideTheView:)];
[self.view addGestureRecognizer:tap];
tap.numberOfTapsRequired = 1;
//add another gesture to terminate first one
UITapGestureRecognizer *secondGest= [[UITapGestureRecognizer alloc] init];
[tableview addGestureRecognizer:secondGest];
[tap requireGestureRecognizerToFail:secondGest];
[secondGest release];
[tap release];
First of all, this problem did not exist in iOS 4.3. I can still run the program in iOS 4.3 and won't see any problem. Secondly, this is an iPad app.
The problem is that when I hold down an image and drag it, it won't be dragged. It worked in iOS 4.3 but not iOS 5.
I created new testing project and cleared everything that's not needed. The project I chose is a Single View Application and did not alter any of the AppDelegate files.
Here is the code.
myUIScrollViewClass.h
#import <UIKit/UIKit.h>
#interface myUIScrollViewClass : UIScrollView
{
}
#end
myUIScrollViewClass.m
#import "myUIScrollViewClass.h"
#implementation myUIScrollViewClass
- (id)init
{
self = [super init];
if (self)
{
}
return self;
}
- (void)didReceiveMemoryWarning
{
[self didReceiveMemoryWarning];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesBegan: touches withEvent:event];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesMoved: touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesEnded: touches withEvent:event];
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.nextResponder touchesCancelled: touches withEvent:event];
}
#end
ViewController.h
#import <UIKit/UIKit.h>
#import "myUIScrollViewClass.h"
#interface ViewController : UIViewController <UIScrollViewDelegate>
{
myUIScrollViewClass *mainScrollView_;
UIImageView *aTouchedImage_;
}
#property (retain, nonatomic) myUIScrollViewClass *mainScrollView_;
#property (retain, nonatomic) UIImageView *aTouchedImage_;
#end
ViewController.m
#import "ViewController.h"
#implementation ViewController
#synthesize mainScrollView_;
#synthesize aTouchedImage_;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
mainScrollView_ = [[myUIScrollViewClass alloc] initWithFrame:self.view.frame];
[self.view addSubview:mainScrollView_];
mainScrollView_.delegate = self;
mainScrollView_.contentSize = CGSizeMake(1024, 768);
mainScrollView_.clipsToBounds = YES;
mainScrollView_.bounces = NO;
mainScrollView_.bouncesZoom = NO;
mainScrollView_.showsVerticalScrollIndicator = NO;
mainScrollView_.showsHorizontalScrollIndicator = NO;
mainScrollView_.backgroundColor = [UIColor whiteColor];
mainScrollView_.userInteractionEnabled = YES;
aTouchedImage_ = [[UIImageView alloc] initWithImage: [UIImage imageNamed:#"image1.png"]];
[aTouchedImage_ setFrame:CGRectMake(0, 0, 80, 80)];
[mainScrollView_ addSubview:aTouchedImage_];
[aTouchedImage_ setCenter:CGPointMake(512, 334)];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return YES;
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)anEvent
{
mainScrollView_.scrollEnabled = NO;
for (UITouch *touch in touches)
{
[aTouchedImage_ setCenter:[touch locationInView:self.view]];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)anEvent
{
mainScrollView_.scrollEnabled = NO;
for (UITouch *touch in touches)
{
[aTouchedImage_ setCenter:[touch locationInView:self.view]];
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)anEvent
{
mainScrollView_.scrollEnabled = YES;
for (UITouch *touch in touches)
{
}
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)anEvent
{
mainScrollView_.scrollEnabled = YES;
for (UITouch *touch in touches)
{
}
}
#end
It seems I will answer my own question.
I have requested a support from Apple Developer Technical Support, and they told me to place my code in the UIScrollView rather than passing the touch events to another view. Apple themselves admitting that there is a problem with passing touch events.
Here is an extract of their reply:
"It looks like not all touch events are getting through to your view controller. Your UIScrollView is blocking touch events from getting through, even though is forwards those events to the next responder. The behaviour is very erratic, some touch events are being forwarded to your view controller, but not all of them."
"Looks like a behaviour change in iOS 5.0.x. My guess it's because of the view controller containment feature that was introduced."
The other way to do it is to use UIGestureRecognizer to implement dragging of views. Something like the code below:
- (void)viewDidLoad
{
// ... other initialization code here
UILongPressGestureRecognizer *longPress = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(dragChild:)] autorelease];
[longPress setMinimumPressDuration:0]; // recognize immediately when a finger comes down
[draggableView addGestureRecognizer:longPress];
}
- (void)dragChild:(UILongPressGestureRecognizer *)longPress
{
[[longPress view] setCenter:[longPress locationInView:[[longPress view] superview]];
}
I have a view in which I have several large buttons which I set up like this:
SwipeButton* btn = [[[SwipeButton alloc] initWithFrame:CGRectMake(55, 0, 300, 50)] autorelease];
btn.tag = k;
[btn setBackgroundImage:[UIImage imageNamed:[NSString stringWithFormat:#"titleBackground.png"]]
forState:UIControlStateNormal];
[btn addTarget:self
action:#selector(indexAction:)
forControlEvents:UIControlEventTouchUpInside];
I would like to be able to either touch these buttons and then fire the indexAction method, or - if a swipe was recognised - to fire another method.
I thought I subclass UIButton to have swipes come through, but this isn't really a solution as now both swipes and clicks are recognised, so BOTH methods fire.
Is there a way around this? How can I prioritise the swiping and only allow the touchupinside if there was NO SWIPE?
Any help would be very much appreciated.
Here is how I subclassed the UIButton:
#import "SwipeButton.h"
#implementation SwipeButton
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
[self.superview touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
[self.superview touchesMoved:touches withEvent:event];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
[self.superview touchesEnded:touches withEvent:event];
}
#end
I don't think that you need to subclass UIButton class. Why don't you try something like this:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
UIImage *image = [UIImage imageNamed:#"picture_0.png"];
[button setImage:image forState:UIControlStateNormal];
[button setFrame:CGRectMake((applicationFrame.size.width - image.size.width)/2, applicationFrame.size.height/2, image.size.width, image.size.height)];
[button addTarget:self action:#selector(buttonTapped:) forControlEvents:UIControlEventTouchUpInside];
UISwipeGestureRecognizer *recognizer;
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:UISwipeGestureRecognizerDirectionRight];
[recognizer setDelegate:self];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
recognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(handleSwipeFrom:)];
[recognizer setDirection:UISwipeGestureRecognizerDirectionLeft];
[recognizer setDelegate:self];
[[self view] addGestureRecognizer:recognizer];
[recognizer release];
Then you create the methods to handle taps and swipes on the button:
// Prevent recognizing touches on the slider
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]) {
return YES;
}
return NO;
}
-(void)handleSwipeFrom:(UISwipeGestureRecognizer *)recognizer {
if ([recognizer direction] == UISwipeGestureRecognizerDirectionLeft) {
// Handle left swipe
NSLog(#"left swipe");
} else {
// Handle right swipe
NSLog(#"right swipe");
}
}
- (void)buttonTapped:(id)sender {
NSLog(#"button pressed");
}
First of the three previous method is declared in a protocol, so don't forget to say that your class is implementing that protocol:
#interface MyViewController : UIViewController <UIGestureRecognizerDelegate>
It works, I just tried it myself. Hope it helps! ;)
Take a look at the UIGestureRecognizer documentation and related examples (e.g.).