Objective C - Tap Gesture counting - ios

I have some imageViews on my View, now I want to change the background.color of the image in my imageView. By clicking second time on the same imageView it should change to the first image.
How I can do this ?

Keep a BOOL or enum ivar to keep track of the image state. When reacting to the tap, exchange the image.
You could have a custom subclass of image view to keep this state always associated with the right object.
// .h
typedef enum { StateOriginal, StateFlipped } FlipState;
#interface FlippableImageView : UIImageView
#property (nonatomic, assign) FlipState state;
#end
// in view controller
if (flipImageView.state == StateOriginal) {
flipImageView.image = imageFlipped;
flipImageView.state = StateFlipped;
}
else {
flipImageView.image = imageOriginal;
flipImageView.state = StateOriginal;
}
The class could also hold both images and run a nice animation...

You can have a Variable to check how many times your ImageView has been touched.
This can be changed in :
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if (touch.view == imageView) {
// Make that variable ++;
if (variable == 2){
imageView.image = [UIImage imageNamed:#"a.png"];
}
}
}

Related

Enable UserInteraction to some part of UIViewController

I have been researching about it since last 3 to 4 hours but I didn't get any information. My issue is I want to enable userInteraction to some part of the UIViewController.
Description:
I have a UIViewController. I have added 30 tableviews. I have stored one value in the application. If that value is 1 then I have to enable user interaction for tableview1 only and if the value is 2 then tableview2 only ........etc
. Please let me know if I am not clear. Thank you for spending your valuable time. Thanks in advance
A simple way to do it is to subclass UIView and override - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event.
Return NO for the part of the UIView (represented as ignoreRect in the sample) you want the subviews to ignore touches.
#interface InteractionView ()
#property (nonatomic) CGRect ignoreRect;
#end
#implementation InteractionView
- (void)awakeFromNib {
self.ignoreRect = CGRectMake(0.0f, 0.0f, 300.0f, 300.0f);
}
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(self.ignoreRect, point)) {
return NO;
}
return [super pointInside:point withEvent:event];
}
#end
If you need more tweaking for an expected behavior : for exemple return a specific view for a specific zone, return the top view of a specific zone, ... you may use
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(self.ignoreRect, point)) {
return nil; // Edit that part if you want to return a chosen view
}
return [super hitTest:point withEvent:event];
}
Another solution without - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event. is to adding UIButton as a subview to the part of UIView you want to close interaction.
for example if you want to close interaction of the bottom half of view.
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(0, self.view.frame.size.height*0.5f, self.view.frame.size.width, self.view.frame.size.height*0.5);
[self.view addSubview:button];
since it will get the touch events, half of the view will be closed to user interaction.
EDIT
IBOutletCollection(UITableView) NSArray *allTableViews;// get all your tableviews reference to this array. set tag in interface builder for each array to reach later.
then when you want to enable/disable interaction of related tableview
int tagToOpenInteraction = 1;//or whatever it is
for(UITableView *t in allTableViews)
{
if(t.tag == tagToOpenInteraction)
[t setUserInteractionEnabled:YES];
else
[t setUserInteractionEnabled:NO];
}

How to slide from a button to other that call event of both buttons

I have many buttons in the view and 1 method with a different parameter for all of that buttons (when touched down)
Now I want to slide from a button to others that this method can be triggered for each button.
For example I slide from button 1 to button 5, the method can be triggered 5 times with parameter from 1 to 5.
I have many buttons, so I can't use touchesMoved.
These are the buttons:
First create your button list as a instance variable:
NSMutableArray *_buttonList;
in viewDidLoad:
_buttonList = [[NSMutableArray alloc] init];
Then:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
[_buttonList removeAllObjects];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = touches.anyObject;
UIView *touchView = touch.view;
if ([touchView isKindOfClass:[UIButton class]]
&& ! [_buttonList containsObject:touchView])
{ // add any additionnal check you may want
[_buttonList addObject:touchView];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
for (UIButton *button in _buttonList) {
[button sendActionsForControlEvents:UIControlEventTouchUpInside];
}
}
Add buttons in a view and add tags to all better in increasing order then(You can map array entry with a button) add add panGestureRecognizer in that view. On handler method check panGesture state if its began or ended. And then get location of pan.
Now you can loop over buttons and check which button frame lies at that position and you will know which button is at that position.
You can do this for both states to get start and end button, loop from startButtonTag to endButtonTag and UIButton *button = (UIButton*)[view viewWithTag:tag] and then can call method by sending that button as parameter.

how to disregard touch events in topmost uiview when it is clear and a different uiview can handle them

I have a clear UIView which has gesture recognizers attached to it.
This clear uiview covers the entire super view to allow for the gestures to be invoked from anywhere on it.
Under this clear UIView sit different components such as tables,buttons,collectionview etc.
The clear UIView has no idea what is under it any time.
What I want - if a view which is under the clear uiview can handle a touch event (or any type of gesture) - the clear view should disregard that event - and the event will pass through to the underlying view which could handle it.
I tried
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
but I don't know how to make sure the underlying view can handle it.
-(id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
id hitView = [super hitTest:point withEvent:event];
if (hitView == self)
{
return nil;
}
else
{
return hitView;
}
}
Add this to your to clear view.
If the hit on clear view means just return nil.
You can override pointInside: withEvent: method. This method returns a boolean value indicating whether the receiver contains the specified point. So if we return NO then your upper clear view will become transparent for touch events and they will be passed to underlying views.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
// Clear UIView will now respond to touch events if return NO:
return NO;
}
use below code for your case->
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{
UIView *hitTestView = [super hitTest:point withEvent:event];
if(hitTestView!=nil){
//check for gesture
if([hitTestView.gestureRecognizers count]>0)
return hitTestView;
//if it is subclass of UIControl like UIButton etc
else if([hitTestView isKindOfClass:[UIControl class]])
return hitTestView;
//if can handle touches
else if([hitTestView respondsToSelector:#selector(touchesBegan:withEvent:)])
return hitTestView;
else
return nil;
}
else{
return self;
}
}
In the above code if the subView which is hitView can anyway handle touch ,we return that object to handle that touch. If there is no such hitTest view, then we return the view itself.
I used some of these suggestions and used the following solution:
I added the gesture recognizer to the bottom most superview in the heirarchy (and not the top most)
Then in that class over rid
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *v = [super hitTest:point withEvent:event];
// if v is nil then touch wasn't in this view or its subviews
if (v == nil)
{
return nil;
}
// in any case if the topview was hidden than return the default value
if (self.myTopView.hidden)
{
return v;
}
// if the view isn't hidden but the touch returned a control - than we can pass the touch to the control
if ([v isKindOfClass:[UIControl class]])
{
return v;
}
// decide on what threshold to decide is a touch
CGFloat threshHold = 40;
// if the touch wasn't on a control but could initiate a gesture than that view should get the touch
if (v.gestureRecognizers)
{
threshHold = 30;
// return v;
}
// check if the threshold should be bigger
if ([self someCondition])
{
threshHold = 100;
}
// threshold according to its position - this is the dynamic part
if (point.y > (self.myTopView.frame.origin.y - threshold))
{
return self.handleBarView;
}
return v;
}

How to compare UIImageView name in an if() structure

I have some UIImageView's that i want to move around the screen. But the problem is that the background image is also an UIImageView, and therefor also drag able. I know that this != (not equal to) syntax below is not right, so I hope someone inhere can give tell me how to do it.
ViewController.h :
#interface ViewController : UIViewController{
IBOutlet UIImageView *circle;
IBOutlet UIImageView *star;
IBOutlet UIImageView *triangle;
IBOutlet UIImageView *background;
}
ViewController.m :
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
UITouch *drag = [[event allTouches] anyObject];
if([touch view] != background){ <---- LOOK HERE
[touch view].center = [drag locationInView:self.view];
}
}
Hope to find some help, and thanks in advance :)
You typically don't want to compare objects with normal (in)equality operators, but in this case I think your code will work fine. When you compare objects, the pointer address is compared, so
if (obj1 == obj2) {
// …
}
will only evaluate to TRUE if obj1 and obj2 are the same instance, which they are in this case.
If you want, you can use the isEqual: method:
if ([obj1 isEqual:obj2]) {
// …
}
This test will include the above one, so there's no reason not to use this. This method will also test class equality, and add specific comparisons for the object type. For example, if you compare two NSString objects, the length of the string and the Unicode characters that make up the string must be identical to evaluate to TRUE.
In this particular case, though, either will work.
The easiest way to identify your objects is with tags,
assign a tag to your imageViews
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
[touch locationInView:viewBoard];
if([touch.view isKindOfClass:[UIImageView class]]) {
UIImageView *tmp = (UIImageView *)touch.view;
if (tmp.tag == imgTag) {
// Your Code
}
}
}
Good Luck!

accessing info from a custom gesture recognizer

I have written a simple custom gesture recognizer like this:
#interface myRecognizer : UIGestureRecognizer {
NSString * _name;
CGPoint _startPoint;
}
- (void)resetMe;
- (void)reset;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
#end
and I have initiated it like this:
myRecognizer *recognizer = [[myRecognizer alloc] initWithTarget:self action:#selector(didRecognize_myRecognizer:)];
[self.view addGestureRecognizer:recognizer];
[recognizer release];
so far so good. and I have my action here:
-(void)didRecognize_myRecognizer:(UIGestureRecognizer*)theRecognizer
{
//do stuff here
}
ok, this is working fine so far, and everything is good. But, here is my question, how can I get access to the _name property I created in my custom gesture in the //do stuff here arear? Basically, I would like to make many gestures, but only have a single method used for the actions, depending on the name of the gesture. In debugging mode I can clearly see the _name variable, but if I try writing code like this: theRecognizer._name, I'm told that there is no "_name" property in UIGEestureRecognizers. if I change the method to this:
-(void)didRecognize_myRecognizer:(myRecognizer*)theRecognizer
{
//do stuff here
}
the same thing happens. and, that wouldn't be good anyway because i want to use the method for all of the gesture recognizers i make. am I clueless? show me the light!
First off, you have to declare an accessor for the instance variable. Dot notation is for properties not instance variables. Declare name as property.
Then, You can check the class of the gesture recognizer and extract the name.
NSString * name = nil;
if ( [theRecognizer isMemberOfClass:[myRecognizer class]] ) {
name = [(myRecognizer *)theRecognizer name];
}

Resources