iPhone:Handling touch event on ImageView: - iphone

I have four imageview in sequence on a screen setting with custom background images. When user touches an imageview (for ex: user touches second imageview), can i get touch notification with which imageview is touched?
I have array of imageview already and placed, and i have to implement touch event and under that identify which imageview is selected.
I want help from some one who can have suggestions to develop this, please suggest me?
thanks.

Using UIButtons as replacements for your UIImageViews is a great idea that Morion mentioned as you can just drag a connection from each button to an outlet in your view controller and handle the action. You can set the background image on the buttons as you are doing currently with the UIImageViews. Set your button type to custom and you'll be good to go.
If, however, you are set on using UIImageView, you will have to subclass UIImageView and override the touch methods you want to intercept. For example:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Call super to make sure you don't lose any functionality
[super touchesBegan:touches withEvent:event];
// Perform the actions you want to perform with the tap.
}

you can use custom buttons instead of UIImages. so it will be easy to find which of them was pressed.

Related

Pass touch from UIScrollView to superview (UIButton)

Possibly a duplicate, but I couldn't find an exact answer to my problem searching SO tonight...
I have a UIButton which contains a UIScrollView, so the button is the superview.
All I want to do is pass a single-tap event from the UIScrollView subview to the UIButton superview, and have the UIButton handle it as it would if the user tapped the button directly.
Setting the scroll view's userInteractionEnabled property to NO won't work for me because there is content the user can scroll. Doing so would defeat the purpose of the scroll view.
Is this possible? Thanks!
Like huoxinbird said, it's definitely not common to lay your views like that.
In the case where you are solidly adamant about this, you could use UITapGestureRecognizer and have it call the button's target and selector.
If you wanted to include the button highlight and such, then you may have to subclass UITapGestureRecognizer and forward the touchesEnded to the button.
Create a subclass of scrollview and override
-(BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
return YES;
}
Also subclass the uibutton(Your superview) and handle touches in touches began.
Usually you don't put scrollview within a button. Instead consider using a UIView as the superview of scrollview. Or tell us more about your use case, so I can understand why you have to design in this way.

How to detect tap on uiview with lots of controls?

My problem is about tap detection.
I have a uiviewcontroller and there are some controls on uiview (labels, buttons, tableview, imageview, etc..)
When I tap the uibutton I display a small uiview (200x150), if the user taps the uibuttons in smallview I hide the smallview.
But I can't hide the uiview if the user taps the background.
I tried this code..
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
//NSLog(#"Touches began.");
[self hideShareView];
}
It doesn't work if I tap the another button in the uiviewcontrols view.
I just want my uiviewcontrol's uiview to react first.
I think its about firstResponder but I dont know how to set it first.
edit: i want it to work like a uiPopover in ipad.
I believe that the correct approach is to add a new transparent UIView when you display your "smallview". You should add a UITapGestureRecognizer to that UIView, in order to trigger the desired selector when the tap is detected. Also, you must ensure that the views are arranged properly, with your smallview being the one at the top, the transparent UIView being immediately below and the rest of the view hierarchy below the transparent UIView.
Finally, you should ensure to remove the transparent UIView from your view hierarchy at the same time that you remove your smallview.
Does that make sense?
Please have a look at this question (how-to-make-a-superview-intercept-button-touch-events), it does seem highly related.
try your hands with bringing your small view (i.e. shareview) to front or sent your main view behind your small view.
If it still doesn't work & you don't want your main view to perform any action when smallview is opened then try
[<YOUR_MAIN_VIEW> setUserInteractionEnabled:NO];
, but MAKE SURE you can do this only when you don't want your main view to perform any action when smallview is opened

How to steal touches from UIScrollView?

Today on my creative time I did some quite comprehensive research on how to steal touches from a UIScrollView and send them instantly to a specific subview, while maintaining the default behavior for the rest of the scroll view. Consider having a UIPickerView inside of a UITableView. The default behavior is that if you drag your finger over the picker view, the scroll view will scroll and the picker view will remain unchanged.
The first thing I tried was to override
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
and simply not allow the UIScrollView to cancel touches inside the picker view. This works, but it has an unpleasant side effect. You would like the picker view to respond immediately and thus you will have to set delaysContentTouches to NO. The problem is that you don't want the rest of the table view to respond immediately, because if it does the table view cell will always get highlighted for a few milliseconds before the scrolling starts.
The second thing I tried was to override
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
because I had read that the scroll view always returns itself, so that it will "steal" the touches from its subviews and later send them to the subview if they weren't of interest to the scroll view. However, this isn't true anymore. UIScrollView's default implementation of hitTest:withEvent: actually returns the subview that should receive the touch. Instead it uses gesture recognizers to intercept the touches.
So the third thing I attempted was to implement my own gesture recognizer and cause it to fail if the touch was outside of the picker view and otherwise succeed. Then I set all the scroll view's gesture recognizers to fail unless my gesture recognizer failed using the following code:
for (UIGestureRecognizer * gestureRecognizer in self.tableView.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:myRecognizer];
}
This does in fact steal the touches from the scroll view, but the picker view never receives them. So I though maybe I could just send all the touches that my gesture recognizer receives using this code:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
[touch.view touchesBegan:touches withEvent:event];
}
The above code is a simplified version. I also make sure that the view is a picker view (or one of it's subviews) and set the appropriate state for the gesture recognizer as I mentioned above. I also did the same for canceled, ended and moved. However, the picker view was still not responding.
I also tried one last thing before returning to my regular work. During my extensive googling I read that nested UIScrollViews just magically worked since 3.x, so I tried putting my picker view inside a nested UIScrollView and set the following properties on it:
scrollView.delaysContentTouches = NO;
scrollView.canCancelContentTouches = NO;
As one would expect the outer scroll view didn't treat the inner scroll view any different than it treated the picker view, so the inner scroll view did not receive the touches. I thought that it was a long shot, but it was simple enough to implement, so I thought it was worth to give it a shot.
What I know is that UIScrollView has a gesture recognizer named UIScrollViewDelayedTouchesBeganGestureRecognizer that intercepts the touches and sends them to the appropriate subview after 150 (?) ms. I'm thinking that I should be able to write a similar recognizer that causes the scroll view's default recognizers to fail and instead of delaying the touches immediately sends them to the picker view. So if anyone knows how to write such a recognizer please let me know and if you have any other solution to the problem, you're very welcome share that as well.
Thank you for reading through the whole question and even if you don't know the answer you could still upvote the question so that it gets more attention (hopefully from someone that can answer it). Thanks! :)
Sometimes you have to ask the question before you can find the answer. Dan Ray had a similar problem and solved it with a very different solution.
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView* result = [super hitTest:point withEvent:event];
if ([result.superview isKindOfClass:[UIPickerView class]])
{
self.scrollEnabled = NO;
}
else
{
self.scrollEnabled = YES;
}
return result;
}
I've tested the code and it works fine for me as well. However, this is not really stealing touches from the scroll view, so if anyone knows how to actually steal touches that would be great.
Source:
UIPickerView inside UITableView.tableFooterView doesn't receive drag touches
A bit late, but I found this solution:
http://www.cocoanetics.com/2010/06/hacking-uiscrollview-gesture-recognizers/
Works for me
I'm also late to the party, but for newcomers, if you're just looking to flat out ignore swipes on the scroll view, what worked for me was to add a pan gesture recognizer to the view I want ignoring the swipes, like this:
let panGesture = UIPanGestureRecognizer()
panGesture.cancelsTouchesInView = false
myView?.addGestureRecognizer(panGesture)

iPhone: Handling touches transparently

I have a UIViewController and an associated with it UIView. The UIView has a number of subviews.
How to handle touch event inside a specified rectangle in my UIViewController subclass?
This handling should be transparent: UIView and its subviews should still receive their touch events even if they intersect with the specified rectangle.
P.S.
Overriding touchesBegan in the view
controller doesn't work. Inner views
doesn't pass events through.
Adding a custom
button to the end of UIView subviews
list also doesn't work. Inner
subviews doesn't receive touch
events.
touchesBegan/touchesMoved/touchesEnded is probably the way to go. Depending on exactly what you are trying to do, UIGestureRecognizer may also be an option.
To make sure subviews pass events up, set userInteractionEnabled to YES on the subviews.
UIView sets this to YES by default, but some subclasses (notably UILabel) override this and set it to NO.
Just because the views don't pass events through by default doesn't necessarily mean that's the way it has to be.
You could subclass the views that you are using and have them pass the events onto the view controller.
Another idea is to literally have a transparent handler on top of all of your views. That is, have a transparent UIView that sits above your views, handling touch events but also passing them through. I have no idea if this works in practice, but it sounds like it would.
Your views, and their controllers can handle a touch using touchesBegan, touchesEnded or touchesMoved. Within touchesBegan as an example you can then choose to pass the event to
the next responder in the responder chain. This way each of your views will get a chance to do something based on the touch event.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//do something here and then pass the event on
[self.nextResponder touchesBegan:touches withEvent:event];
}

What can be the reason that my UIImageView subclass doesn't receive any touch events?

I have made sure that all superviews of my customized UIImageView and the UIImageView itself have userInteractionEnabled = YES;
Also in the nib all views and subviews have userInteractionEnabled = YES;
But for some reason, these get never called when I click on the UIImageView:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"check!");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"other check");
}
I have an UIView that acts as an grouping for some subviews. Can that be a problem?
This is just a guess -- is there a UIScrollView somewhere in the view hierarchy? UIScrollViews don't pass touch events like normal views, you have to subclass it and implement a custom touchesBegan method. You can find information about that here -- it's a problem that sent me scratching my head and Googling for several hours the first time I encountered it.
After a while I figured out the following problem:
I had an UIView that I used to group some UIImageViews together, so that I can move all of them at once by moving that UIView only. I made the UIView 0.01 x 0.01 big while it does not clipsToBounds. As I clicked on subviews that were drawing outside the bounds of their superview, the UIView, no touch events where received on these subviews. I don't know if there were any touch events at all.
So, if you have the same problem, make sure that your touches occur on an area which fits into the superview. In my case, I just made that grouping UIView bigger, making the touch-sensible area bigger. After that, it worked. I now slightly remember that Apple had mentioned that in the documentation somewhere, that subviews may draw outside of their superviews, but touch events will be recognized only if they happen in the rectangle of the superview.
It looks like you have a typo there: the correct selector name is 'touchesBegan'. Are you adding this view programatically or through a nib?
touchesBegun should be touchesBegan, but I think that's just a typo?
Depsite that, usually touches not coming through indicates a stressed CPU. Try testing the performance of your app with Instruments.