how to recognise Single tap using UIWebView - iphone

I am using UIWebView to show a pdf file in my MainViewController. On single tap I want to load a new View to the MainViewController.
But the UIWebView is not allowing default UITouch event
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
}
How to solve this problem?
Regards

UIWebView a is subclass of UIScrollView.
You can use touchesShouldBegin:withEvent:inContentView: method defined in UIScrollView documentation.
You need to define this method in your UIWebView own class:
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view {
// DO SOMETHING
return NO;}

#Pierre
Thanks
I did the following :
#implementation UIViewTouch
. . .
- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
// DO SOMETHING
return NO;
}
In the view controller implementation:
-(void)viewDidLoad
{
CGRect frame = CGRectMake(0, 0, 500, 1000);
UIViewTouch *viewTouch = [[UIViewTouch alloc]initWithFrame:frame];
NSString *urlAddress = [[NSBundle mainBundle] pathForResource:#"page1" ofType:#"pdf"];
NSURL *url = [NSURL fileURLWithPath:urlAddress];
NSURLRequest *requestObj = [NSURLRequest requestWithURL:url];
[viewTouch loadRequest:requestObj]; [self.view addSubview:viewTouch];
}

Create a UIView sub class containing the whole UIWebView. Then the event hitTest will be fired on touching the webview.
Note: Don't put anything to the container except the webView.
#interface myWebViewContainer : UIView
... ...
#end
Then override the hitTest event:
-(UIView*) hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
NSLog(#"Hit test %#", [event description]);
UIView * returnView = [super hitTest:point withEvent:event];
[delegate userDidTapWebView];// notify the delegate that UIWebView is being touched by some naughty user :P
return returnView;
}

Ideally webView userInteractionEnabled should be set to NO and on top of the web view that is the view controller. We can use a TapGesture which will load another view.

Related

how to dismiss a UIPickerView in ios

In my app, i have pickerviews in my add contact page. I have given the following 'touchesBegan' method. But it dismisses the picker even when i click on a value to set. For example, if i click 'homephone' from preferred phone picker, the picker gets dismissed instead of setting the value. i need the picker to be dismissed only if i click outside the picker. Can anyone help me in fixing this.
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.AddView endEditing:YES];
}
You can use
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] != pickerview)
[self.AddView endEditing:YES];
}
this will be used to endedit when the touch is outside the picker view
try this code:
UITapGestureRecognizer *single_tap_recognizer;
single_tap_recognizer = [[[UITapGestureRecognizer alloc]
initWithTarget : self.view
action : #selector(upper_button_view_tapped)]
autorelease];
[single_tap_recognizer setNumberOfTouchesRequired : 1];
[self.view addGestureRecognizer : single_tap_recognizer];
-(void)upper_button_view_tapped
{
[self .view endEditing:YES];
}
Hope it help You
In your code:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self dismissViewControllerAnimated:YES completion:nil];
}
Or You can put a bigger button under the PickerView, make it color clear custom and dimension full screen, then use the dismiss inside a (IBAction) and when you tap outside the picker your view is dismissed
- (IBAction)buttonClear:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}

How to resize child view of a scroll view when zooming in iphone sdk

I have a scroll view with an image. User can touch the scrollview and place rectangle views on it. I want that when user pinch zoom a scroll view then the child subviews should automatically resize according to the ratio. Also user should be able to move or resize the child views with touch events. This is working fine when scroll view is not zoomed but when scroll view is zoomed then the child view cant be resized or dragged as the whole scroll view moves. I tried to change the frame size of child view according to the scroll view size but it is not giving proper results .
Is there any way to recieve touch events when scroll view is zoomed
Thanks in advance
#interface UIZoomingViewController : UIViewController <UIScrollViewDelegate>
#property (strong, nonatomic) UIView* substrate;
#end
#implementation UIZoomingViewController
-(id)init /*your init method*/
{
if(self = [super init])
{
UIScrollView* scrollView = ((UIScrollView*)self.view); /*controller view - UIScrollView*/
[scrollView setDelegate:self];
/*set contentsize, min max zoom scale*/
_substrate = [UIView alloc] initWithFrame:scrollView.bounds];
[scrollView addSubview:_substrate];
/*
if you need zoom view, add to substrate
[_substrate addSubview:...];
*/
}
return self;
}
#pragma mark - UIScrollView delegate implementation
-(UIView*)viewForZoomingInScrollView:(UIScrollView*)scrollView
{
return _substrate;
}
#end
and little trick, if you need to receive touches after UIScrollView, create subclass...
#interface UINewScrollView : UIScrollView
#end
#implementation UINewScrollView
-(BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
return YES;
}
-(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];
}
#end

touchesMoved detection inside a subview

I am trying to detect touches inside a subview
In my main viewcontroller I am adding a subview called:SideBarForCategory, it takes 30% of the screen from the left - as a sidebar.
SideBarForCategory *sideBarForCategory = [[SideBarForCategory alloc] initWithNibName:#"SideBarForCategory" bundle:nil];
[sideBarData addSubview:sideBarForCategory.view];
inside SideBarForCategory, I would like to test for touches
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self.view] anyObject];
CGPoint location = [touch locationInView:touch.view];
NSLog(#"Map Touch %f",location.x);
}
The above code (touchesMoved) works perfectly on the main view (viewcontroller) but does not work inside my subview (SideBarForCategory) - why and how can I fix it?
Two possible solutions i can think of :
Either use GestureRecognizers (eg. UITapGestureRecognizer, UISwipeGestureRecognizer) and add those recognizers to your SideBarForCategory view.
Generic gesture handling : Create your own custom subclass of UIView for example MyView and add those touch methods inside it. Then create SideBarForCategory view as an instance of MyView.
Hope it works :)
Updated :
For second option :
#import <UIKit/UIKit.h>
#interface MyView : UIView
#end
#implementation MyView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// No need to invoke |touchesBegan| on super
NSLog(#"touchesBegan");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
// invoke |touchesMoved| on super so that scrolling can be handled
[super touchesMoved:touches withEvent:event];
NSLog(#"touchesMoved");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[super touchesEnded:touches withEvent:event];
NSLog(#"touchesEnded");
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
/* no state to clean up, so null implementation */
NSLog(#"touchesCancelled");
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
Update :
And then in your SideBarCategoryView class implementation , inside loadView()
self.view = [[MyView alloc] init];
check Apple's references for converting points. You probably forget to convert the point relevant to your subview. Therefore it is trying to check the absolute coordinates of the touch point.
Probably what you need is :
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view

Getting Access to the touch event in an UIAlertView

I am displaying a Customized UIAlertView. I need to know how to get access to the touch events taking place in that AlertView.
I have a controller class which is set as the delegate of my customized UIAlertView, with the following method, but this is not triggered on touching being taking place in AlertView.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
Another solution (instead of overriding UIView and - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event) could be the usage of UIGestureRecognizer.
UIGestureRecognizers are very powerful and worth a look anyway.
In this case you don't have to deal with inheritance, but can add it to any view.
- (id)initWithFrame:(CGRect)frame {
if ((self = [super initWithFrame:frame])) {
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(tapGestureDetected:)];
[self addGestureRecognizer:tapRecognizer];
}
return self;
}
- (void) tapGestureDetected:(UITapGestureRecognizer*)recognizer {
int numberOfTapAreas = [self.delegate numberOfTabAreas];
CGPoint p= [tapRecognizer locationInView:recognizer.view];
//...
}

Handling touches inside UIWebview

I have created a subclass of UIWebView , and have implemented the
touchesBegan, touchesMoved and touchesEnded methods.
but the webview subclass is not handling the touch events.
Is there any method to handle the touch events inside the UIWebView subclass ???
No subclassing needed, just add a UITapGestureRecognizer :
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(didTapMethod)];
[tap setNumberOfTapsRequired:1]; // Set your own number here
[tap setDelegate:self]; // Add the <UIGestureRecognizerDelegate> protocol
[self.myWebView addGestureRecognizer:tap];
Add the <UIGestureRecognizerDelegate> protocol in the header file, and add this method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
If all you need is to handle gestures, while leaving the rest of the UIWebView functionality intact, you can subclass UIWebView and use this strategy:
in the init method of your UIWebView subclass, add a gesture recognizer, e.g.:
UISwipeGestureRecognizer * swipeRight = [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(handleSwipeGestureRightMethod)];
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[self addGestureRecognizer:swipeRight];
swipeRight.delegate = self;
then, add this method to your class:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
Add and handle your designated selector to the class, in this case "handleSwipeGestureRightMethod" and you are good to go...
You could put an UIView over your UIWebView, and overide the touchesDidBegin etc, then send them to your webview. Ex:
User touches your UIView, which provokes a
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// Execute your code then send a touchesBegan to your webview like so:
[webView touchesBegan:touches withEvent:event];
return;
}
your UIView has to be over the webview.
I'm not sure if this is what you want (it's not what you asked for, but it might work depending on what your end game is), but you could instead interpret the touches in JavaScript from inside the UIWebView, and get javascript to do
document.location='http://null/'+xCoord+'/'+yCoord; // Null is arbitrary.
Then you can catch that using the UIWebView's delegate method
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
And if the request.URL.host (or whatever it is) isEqualToString:#"null" take the relevant action (and return NO instead of YES). You can even add the JS to each page by doing something like:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[webView stringByEvaluatingJavaScriptFromString:#"window.ontouchstart=function(/* ... */);"];
}
Hope this helps?
Handling gestures on a UIWebView is discussed in this Apple Developer forum thread.
Using the info given there, there will be no need for an extra view in most or all cases, and as mentioned here before, overriding UIWebView is not the way to go.
Copypaste of the most important post in the thread:
This is a known issue. The UIWebView has its own UITapGestureRecognizers, and they're on a private subview of the UIWebView itself. UIGestureRecognizer precedence defines that gestures attached to views deeper in the view hierarchy will exclude ones on superviews, so the web view's tap gestures will always win over yours.
If it's okay in your case to allow your tap to happen along with the web view's normal tap your best solution would be to implement the UIGestureRecognizerDelegate method gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer and return YES for other tap gestures. This way you'll get your tap handler called, and the web view will still get its called.
If you need to be the only one handling the tap you'll have to subclass UITapGestureRecognizer so you can use the one-way overrides in UIGestureRecognizerSubclass.h, an you can then return NO from canBePreventedByGestureRecognizer: when asked if the web view's tap gesture recognizer can prevent yours.
In any case, we know about this and hope to make it easier in the future.
I've just found that UIWebView does check whether it responds to the - (void)webViewDidNotClick: (id)webBrowserView selector, once one taps on the view area (not on hyperref, or any other area that should be handled specifically). So you may implement that selector with your handling code :)
Do you mean your sub-classed implementation is not called when touchesBegan, touchesMoved and touchesEnded are called?
It sounds like a problem with how you've created an instance of the object. More details are required I think.
(taken form comments)
Header File
#import <UIKit/UIKit.h>
#interface MyWebView : UIWebView { } #end
Implementation File
#import "MyWebView.h"
#implementation MyWebView
- (id)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) { } return self;
}
- (void)drawRect:(CGRect)rect {
NSLog(#"MyWebView is loaded");
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"touches began");
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(#"Touches ended");
}
- (void)dealloc {
[super dealloc];
}
#end
I would try overriding -sendEvent: on UIWindow, to see if you can intercept those touch events.
Following on from what Unfalkster said, you can use the hitTest method to achieve what you want, but you don't have to subclass UIWindow. Just put this in your web view subclass. You will get a compile time warning but it does work:
- (void)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
if (event.type == UIEventTypeTouches) {
// get location info
CGFloat x = point.x;
CGFloat y = point.y;
// get touches
NSSet *touches = [event allTouches];
// individual touches
for (UITouch *touch in touches) {
if (touch.phase == UITouchPhaseBegan) {
// touches began
} else if (touch.phase == UITouchPhaseMoved) {
}
// etc etc
}
}
// call the super
[super hitTest:point withEvent:event];
}
Hope that helps!
If you want to detect your own taps but disable the UIWebView's taps then you can use my solution:
-(void)recursivelyDisableTapsOnView:(UIView*)v{
for(UIView* view in v.subviews){
for(UIGestureRecognizer* g in view.gestureRecognizers){
if(g == self.ownTapRecognizer){
continue;
}
if([g isKindOfClass:[UITapGestureRecognizer class]] ||
[g isKindOfClass:[UILongPressGestureRecognizer class]] ||
[g isKindOfClass:NSClassFromString(#"UITapAndAHalfRecognizer")]){
g.enabled = NO;
}
}
[self recursivelyDisableTapsOnView:view];
}
}
- (void)webViewDidFinishLoad:(UIWebView *)webView{
[self recursivelyDisableTapsOnView:webView];
//disable selection
[webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.style.webkitUserSelect='none';"];
// Disable callout
[webView stringByEvaluatingJavaScriptFromString:#"document.documentElement.style.webkitTouchCallout='none';"];
}