UIWebView's inside UIScrollView consuming touch events - objective-c

I have multiple custom UIWebView's as subviews within a UIScrollView. I have implemented the touch methods within the UIViewController for the UIWebView's, but these methods are not being called.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { }
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { }
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { }
I have read elsewhere and it says that the UIScrollView will consume the events. This makes sense, but should the UIWebView's not receive the touch event before the UIScrollView itself? What is probably happening, is that the UIWebBrowserView (a subview of the UIWebView) is consuming the events. This class can't be subclassed however, and so I can't send the events up the superview chain to the UIScrollView. I have read on the Apple iOS Documentation that one shouldn't ever place a UIWebView inside a UIScrollView, but I need to do so for my purposes.
So my question is: how can my custom UIWebView's (that are subviews of a UIScrollView) receive touch events?
My controllers and views are set up as follows:
HomeViewController.h /.m /.xib
HomeView.h /.m (is a UIScrollView)
DashboardViewController.h /.m /.xib (custom UIWebView's)
HomeViewController is loaded from a Nib file that contains a custom view: HomeView.
DashboardViewController is loaded from a Nib file. It contains a few labels, sliders, etc. (note that there is no custom view here - I am not subclassing UIView here).
HomeViewController dynamically loads several DashboardViewControllers and adds its view to the HomeView.
DashboardViewController *dashboardViewController = [[DashboardViewController alloc] initWithNibName:#"DashboardViewController" bundle:[NSBundle mainBundle];
[homeView addSubview:dashboardViewController.view];

You are probably looking for canCancelContentTouches.
scrollView.canCancelContentTouches = NO;

The User Interaction is standard enabled.
Did you connect your views delegate to the File's Owner?
And did you bind your View to the Controller? And make sure you connect the corresponding actions to the correct methods. (CTRL Click on the View and drag the plus sign onto the corresponding method in your Class.h file.
#interface MyScrollView : UIViewController {
UIView *myFirstView;
UIView *mySecondView;
UIView *myThirdView;
}
#property (nonatomic, retain) IBOutlet UIView *myView;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
#end

Have you set userInteractionEnabled = YES for all the subviews?

UIViewController gets the touches* messages before the UIView. The UIViewController doesn't pass the message along to the UIView (by calling [super touchesBegan]) by default. So you need to move or forward the touches* functions if your UIView has a controller.
Personally I put the various touches* methods on the view subclass, not the view controller subclass.

You can try this, when you get the touches methods being called for UIScrollView in turn you can call the same touches method in subview from scrollview.

Related

Resend touch event to another view in iOS

I've got an UIImageView on top of (and not an element of) a UIScrollView. Well, I've subclassed the UIImageView to check for touch events and have overridden the touchesBegan:withEvent: method. Inside that method I basically send the subclassed UIImageView behind the UIScrollView element. (I use [self.super bringSubviewToFront: scrollView] to achieve this).
What I want is to be able to send the current touch event of the UIImageView to the UIScrollView element, so that the user doesn't have to lift his finger and touch again to scroll. I already tried to call touchesBegan:withEvent: on the UIScrollView element, but it did nothing.
Does anyone have an idea of what should be done so I could simulate the touch of the UIImageView to the UIScrollView element?
Here is the overridden method in the subclassed UIImageView:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesBegan: touches withEvent: event];
ViewController* controller = [Singleton getSingleton].controller;
[super bringSubviewToFront: controller.scrollView]; //Now scroll view is in the front
[controller.scrollView touchesBegan: touches withEvent: event]; //Does nothing
}
I need to override hitTest:withEvent: in the UIImageView subclass.
(UIView*) hitTest: (CGPoint)point withEvent: (UIEvent*)event
{
if([self pointInside:point withEvent:event]){
ViewController* controller = [Singleton getSingleton].controller;
[controller.view bringSubviewToFront: controller.scrollView];
return controller.scrollView;
}else{
return [super hitTest:point withEvent: event];
}
}
This way, when a touch on the UIImageView is issued, it would first call this method, which would bring the UIScrollView to front and then return the UIScrollView as the object which should handle the event.

iOS - touchesMoved called only once in subclassed UIScrollView

I am trying to drop movable UIImageViews within a subclassed UIScrollView so that I can drag them around my UIScrollView. I subclassed UISCrollView and the dropping behavior is working, but when I try to drag the images, touchesMoved is only evaluated once. The touchesMoved method in my subclass of UIScrollView looks like this:
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
if (!self.dragging) {
[self.nextResponder touchesMoved: touches withEvent:event];
}else{
[super touchesEnded:touches withEvent:event];
}
}
It is being called continuously during a moving touch, as it should. Can anyone think of a reason that the touchesMoved method in my view controller would only be called once?
IOS 5: UIScrollView not pass touches to nextResponder
Instead of:
[self.nextResponder touchesMoved:touches withEvent:event];
Use:
[[self.nextResponder nextResponder] touchesMoved:touches withEvent:event];

How to stop the UIScrollView get touch events from its parent view?

I have a UIView containing a UIScrollView.
This UIView is supposed to respond to some touch events but it is not responding because of the scrollView it contains.
This scrollView's contentView is set to a MoviePlayer inside the OuterView.
Now whenever I click in the area where the MoviePlayer is, touch events of my OuterView are not responding.
I have even set the movie player's userInteraction to NO.
but now scrollView is interfering it seems.
I have referred to this post on SO itself.
How can a superview interecept a touch sequence before any of its subviews?
But the solution there, asks me to set the userInteractionEnabled to NO for the scrollView
But if I do so, my pinch zoom doesn't take place either!
What to do?
An UIScrollView intercepts all touch events because it has to decide if/when the user has movd their finger in order to scroll the scroll view.
You may want to subclass UIView, then in the
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)evt;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)evt;
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)evt;
methods, check for the neccessary touches, then forward all these methods to your UIScrollViewInstance. For example:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#interface MyView: UIView {
UIScrollView *scrollView;
}
#end
#implementation MyView
/* don't forget to alloc init your ScrollView init -init
and release it in -dealloc! Then add it as a subview of self. */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)evt
{
/* check for a gesture */
[scrollView touchesBegan:touches withEvent:evt];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)evt;
{
/* check for a gesture */
[scrollView touchesMoved:touches withEvent:evt];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)evt;
{
/* check for a gesture */
[scrollView touchesEnded:touches withEvent:evt];
}
#end

prevent UIScrollView to send touches to subview

How can I prevent the UIScrollView to send touches to it's subviews?
your subview.userInteractionEnabled = NO;
Inherit from UIScrollView and define your own hitTest in following way:
#implementation MyScrollView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
return [self pointInside:point withEvent:event] ? self : nil;
}
#end
So, touches will not be forwarded into internal subviews and will stay on a level of UIScrollView.

Detecting UITableView scrolling

I've subclassed UITableView (as KRTableView) and implemented the four touch-based methods (touchesBegan, touchesEnded, touchesMoved, and touchesCancelled) so that I can detect when a touch-based event is being handled on a UITableView. Essentially what I need to detect is when the UITableView is scrolling up or down.
However, subclassing UITableView and creating the above methods only detects when scrolling or finger movement is occuring within a UITableViewCell, not on the entire UITableView.
As soon as my finger is moved onto the next cell, the touch events don't do anything.
This is how I'm subclassing UITableView:
#import "KRTableView.h"
#implementation KRTableView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesBegan:touches withEvent:event];
NSLog(#"touches began...");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesMoved:touches withEvent:event];
NSLog(#"touchesMoved occured");
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent *)event {
[super touchesCancelled:touches withEvent:event];
NSLog(#"touchesCancelled occured");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
NSLog(#"A tap was detected on KRTableView");
}
#end
How can I detect when the UITableView is scrolling up or down?
You don't need to intercept the event methods. Check the docs for the UIScrollViewDelegate protocol, and implement the -scrollViewDidScroll: or -scrollViewWillBeginDragging: methods as appropriate to your situation.
I would like to add the following:
If you are working with a UITableView it is likely that you are already implementing the UITableViewDelegate to fill the table with data.
The protocol UITableViewDelegate conforms to UIScrollViewDelegate, so all you need to do is to implement the methods -scrollViewWillBeginDragging and -scrollViewDidScroll directly in your UITableViewDelegate implementation and they will be called automatically if the implementation class is set as delegate to your UITableView.
If you also want to intercept clicks in your table and not only dragging and scrolling, you can extend and implement your own UITableViewCell and use the touchesBegan: methods in there. By combining these two methods you should be able to do most of the things you need when the user interacts with the UITableView.
It was my mistake, I tried to call the method before reloading the tableview. The following code helped me solve this issue.
[mytableview reloadData];
[mytableView scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:btn.tag-1] atScrollPosition:UITableViewScrollPositionTop animated:YES];