I am using a custom webview to show a tabbar when user touches on the webview. But when I clicked on a link in a webview, tabbar is shown for a little time and then page loads. I am using this custom webview to detect touch: http://github.com/psychs/iphone-samples/blob/b772b963f2acf18d478b41b44555992fcd8d4f31/WebViewTappingHack/Classes/PSWebView.m
Can I detect if a link clicked or not? Because a link stands on the webview, webview detects the touch and also it loads the page... I want to prevent it.
Thanks in advance.
Using Javascript
Instead of preventing the loading of the page, I would inject Javascript into the webview so that touching the link doesn't do anything.
I've answered a question similar to this not too long ago. Instead of disabling all links (like the other question) just look for the specific link you'd like to disable and remove its href attribute.
Using a UIWebview Delegate
Alternatively, if you want to be able to respond to a user attempting to click the link (perhaps to give them a message), you can set the UIWebview's delegate and implement the webView:shouldStartLoadWithRequest:navigationType: method and return NO if the URL attempting to be loaded is the one you'd like to block.
As an aside, it's usually best practice to maintain a whitelist as opposed to a blacklist for this sort of exclusion. Rather than blocking links you don't want it might be better to block all links, except for the ones you know are safe to navigate to.
UIWebViewNavigationTypeLinkClicked = Tells you when a link has clicked.
Only check you call
self.webView.delegate = self;
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
[[UIApplication sharedApplication] openURL:request.URL];
return NO;
}
return YES;
}
OK, I did a workaround and solved by myself...
My links are at the top & bottom of the page so I got screen coordinates by the following code and if pos.y < some value and pos.y > some value then do not show the menu...
UITouch * touch = [touches anyObject];
CGPoint pos = [touch locationInView: [UIApplication sharedApplication].keyWindow];
NSLog(#"Position of touch: %.3f, %.3f", pos.x, pos.y);
Hope this helps someone...
Related
I am importing all tags of a HTML page to UITextView. but i have few on click events like mail and phone in this HTML tags. how can i detect that on click event and open it in UIWebView.
suppose are you displaying String in UIWebView like bellow But First you must configure your webView outlet and connect proper Delegate then put below code in to ViewWillApear:-
[webview loadHTMLString:[NSString stringWithFormat:#"%# Have an enquiry for %#? Click hear and we will be in touch with you.* {margin:0;padding:0; font-family:Arial;font-size:15px;text-align:justify}", yourStringDiscription,YourHyperlinkWord] baseURL:nil];
in Above script this line:-
:[NSString stringWithFormat:#"<html><body text=\"#000000\">%# <br>Have an enquiry for %#? Click hear
in first %# is for String of contain and second %# for your Hyparlink
Now
you can get click event of this webViewdelegate method
-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( inType == UIWebViewNavigationTypeLinkClicked ) {
//Got even here put breck point
return NO;
}
return YES;
}
you can got click event in above delegate hope you undastood what i am saying and hope its help's you
When you on click events, do you simply mean that you want to make things like the email address, phone # etc to be tappable, such that tapping a phone # would open the Phone app etc?
If so, have you tried simply setting the UITextView's properties in Interface Builder > Attributes Inspector.
See my image below:
The deafult pop up is get opened when I long press the music play option in any url from UIWebView.
I Want to add one more button in the pop up..Is it possible to do it..
Like I want to add FETCH button.
And Can I make changes in the default pop up functioning which is OPEN and COPY. shown below
I come to know that by google -
First of all, you really can’t add additional menu items to the default ones of the standard contextual menu. But you can switch off the contextual menu using a certain CSS property. So the solution would be to switch off the default menu and implement your own from scratch. And to implement your own contextual menu, you have to first catch the tab-and-hold gesture, get the coordinates of the finger on the screen, translate these coordinates into the coordinate system of the web page and finally look for the HTML elements at this location.
NEW ANSWER:
Looks like this is what we want, here:
https://stackoverflow.com/a/3198220/700471
OLD ANSWER:
Okay, after some research, here's the deal:
What you describe in your question seems accurate:
First of all, you really can’t add additional menu items to the
default ones of the standard contextual menu. But you can switch off
the contextual menu using a certain CSS property. So the solution
would be to switch off the default menu and implement your own from
scratch. And to implement your own contextual menu, you have to first
catch the tab-and-hold gesture, get the coordinates of the finger on
the screen, translate these coordinates into the coordinate system of
the web page and finally look for the HTML elements at this location.
So you are planning on implementing your own popover controller with contextual menu--fine, I won't get into that at all, I will assume you know how to do that.
What your question seems to be is, how do you take a long-tap gesture in the UIWebView and transform it into the coordinates of the webpage to find the DOM element that was selected, and use that as a context from which to generate your popover menu.
What I found was this, specifically this with this line of code:
NSString *js = [NSString stringWithFormat:#"document.elementFromPoint(%f, %f).innerHTML", touchPoint.x, touchPoint.y];
That looks like the JS you would need to figure out what element had just been long-pressed, and of course you would need to do some figure-figure to see if it was a link and execute your context menu from there, but that's not something I've looked into.
Some further thoughts:
Probably the easiest course would be to attach a UILongPressGestureRecognizer to your UIWebView (this can be done easily in a nib) and make sure that the "Sent Action" points to an appropriate IBAction on your ViewController. (I suppose you could use the delegate outlet as well, but I have never needed to do that.)
In any case, you can use the locationOfTouch:inView: method of your gesture recognizer, and the view you will probably want to use will be the UIWebView's content view, which I believe you can get with something like myWebView.scrollView.subviews[0] (or the objectAtIndex: variation if you are not using the new array index subscripts).
Anyway, I think I have provided enough to answer your question.
EDIT:
Okay, so you are still having trouble with this, so I went and made a test project and got it to work. One thing that is slightly annoying about this is that WebKit somehow adds a "buffer" area around objects in the DOM, meaning that if you touch slightly next to a link it will still highlight, but when you use the JS command elementFromPoint it doesn't do that, so you kinda have to touch more carefully to trigger the popup using this method. But, it works.
I made a blank project with the "single view" template, and threw a UIWebView into the xib, pointed its delegate outlet to File's Owner. Then I put a UILongPressGestureRecognizer into the xib, attached to the UIWebView. I set its delegate as File's Owner, and set its selector outlet to the longPressDetected IBAction in File's Owner. I also unchecked "Canceled in View" in the recognizer's properties in Interface Builder.
Here is the code for the view controller.
Interface:
//
// WVTViewController.h
// WebViewTest
//
#import <UIKit/UIKit.h>
#interface WVTViewController : UIViewController <UIWebViewDelegate, UIGestureRecognizerDelegate>
#property (nonatomic, weak) IBOutlet UIWebView *myWebView;
#property (nonatomic) BOOL didFirstLoad;
- (IBAction)longPressDetected:(id)sender;
#end
Implementation:
//
// WVTViewController.m
// WebViewTest
//
#import "WVTViewController.h"
#interface WVTViewController ()
#end
#implementation WVTViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// Just load google.
NSURL *theURL = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:theURL];
[self.myWebView loadRequest:request];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
if (!self.didFirstLoad) {
// Disable the default contextual menu.
[webView stringByEvaluatingJavaScriptFromString:#"document.body.style.webkitTouchCallout='none';"];
}
}
// Called by the gesture recognizer.
- (IBAction)longPressDetected:(UILongPressGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateBegan) {
NSLog(#"Long press detected.");
CGPoint webViewCoordinates = [sender locationInView:self.myWebView];
NSLog(#"WebView coordinates are: %#", NSStringFromCGPoint(webViewCoordinates));
// Find the DOM element
NSString *locatorString = [NSString stringWithFormat:#"document.elementFromPoint(%f, %f).innerHTML", webViewCoordinates.x, webViewCoordinates.y];
NSString *result = [self.myWebView stringByEvaluatingJavaScriptFromString: locatorString];
NSLog(#"Element Found: %#", result);
}
}
// Necessary or the gesture recognizer won't call the IBAction.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}
#end
As I said, I tested the above code and it works fine. You can of course change up your JS and use something other than innerHTML, such as tagName or href or whatever you like. Multiple checks may be necessary for what you're trying to do, possibly with queued JS commands (which would be lame), unless you could JSON-stringify the DOM object, pass it back to the Objective-C, convert to native objects and perform your checks in that environment--but, I'm no JS pro and I'm not going to investigate that.
As a note, I was a bit surprised that the coordinates that worked for elementFromPoint were the touch coordinates within the UIWebView itself. I had rigged up a whole block of code that iterated through myWebView.scrollView.subviews and found the content view, then called locationOfTouch:inView: on that view. But I was getting funky behavior, so on a hunch I used the webview coordinates and it worked fine, even on a big webpage when I was scrolled off to the side and down. I suspect that some kind of Apple-programmed behavior inside the webview may translate those coordinates. Possibly the JS's coordinate system is altered based on the way the content view is moved around inside the scrollview--that makes the most sense to me.
The proper and accurate way to answer this question is below link
http://www.icab.de/blog/2010/07/11/customize-the-contextual-menu-of-uiwebview/
you can fire the event with something like this:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
if( navigationType == UIWebViewNavigationTypeLinkClicked )
{
// Handle your URL click here (open the popup menu)
// ...
return NO;
}
return YES;
}
don't forget to delegate the UIWebView
I have a UIView and a UIWebView.
The UIWebView is a child view of the UIView.
The UIWebView contains a youtube video and is set as to let the video fit to the UIWebView.
I have a UITapGesture associated with the parent UIView for single tap, say, if a user single tap the whole view, it will invoke A.
So, when the UIWebView loads the youtube video, there is a button on top of the video waiting for users to click to play. But now if I click the button, the youtube is played, but also the A is invoked too. This is what I don't want.
How should I solve it?
I thought the touch/tap event should be in a order and if the button is clicked, it should absorb the event and not give the UIView any more.
I also tried to add another UIView under the UIWebView, and attach that gesture to the underlying view. However, it still doesn't work.
How can I do to let the button over the youtube video independent?
thanks
Try add this code in your view's .m file (if you are using UIView, subclass it):
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
CGPoint p = [self convertPoint:point toView:webView];
if ([webView pointInside:p withEvent:event]) {
return [webView hitTest:p withEvent:event];
}
return [super hitTest:point withEvent:event];
}
Since I did not try this code, tell me if it doesn't work. There are still many ways to deal with the situation. :)
My app features content that (for text formatting reasons) is presented in an UIWebView. Within the content there are links, some of which should open their target in mobile Safari, while others should navigate within the content.
So far, I've catched the link requests using a UIWebView delegate. In my implementation of
-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
I'd check the requests URL using lastPathComponent or pathComponents for known elements to determine whether to open the link externally or within the view.
However, I just found out said methods are only available since iOS 4.0, which would render the app useless on iPad. Plus I have the feeling I'm using a dirty solution here.
Is there another way to somehow "mark" the links within my content in a way that makes them easy to distinguish later, when processing the request in the delegate method?
Thanks alot!!
You could covert the URL request into a string, and do a compare for a subdirectory on your website, such as in URLs that only start with "http://www.sample.com/myapp/myappswebcontent/", against the initial substring of your URL. Anything else, send to Safari.
You should set a policy delegate of web view:
For instance in the controller, that contains a web view
[webView setPolicyDelegate:self];
and then override a decidePolicyForNavigation method (this is just an example):
- (void)webView:(WebView *)sender decidePolicyForNavigationAction: (NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id <WebPolicyDecisionListener>)listener
{
if ([[actionInformation objectForKey:WebActionNavigationTypeKey] intValue] == WebNavigationTypeLinkClicked) {
[listener ignore];
[[NSWorkspace sharedWorkspace] openURL:[request URL]];
}
else
[listener use];
}
you can distinguish there kind of link and ignore or use the listener. If you ignore it, you can open the link in safari, if you use it, the link will open in your webview.
HTH
I am designing an app which will present large amounts of text that is interspersed with notes and references as clickable images. On a PC I'd use a control that shows HTML, but in the iPhone I am not able to intercept the touches of images and links too well using the UIWeb control.
Should I use a UIScroll and build the text as lables and UIImages perhaps?
Looking for the best way forward in my design phase.
I don't know what your requirements are obviously, but it is possible to capture the click on an link in a UIWebView and take some alternative action. In one of my Apps, I have a UIWebView with one particular link which I want to route differently, while I let all other links open as web pages in the UIWebView as normal. Here's the code snippet from the app which accomplishes this. It is within a UIViewController which loads the UIWebView:
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [ request URL ];
if( [[url path] isEqualToString:#"/the_special_link.html"] ) {
// Take some alternative action and then stop the page from loading...
// (code to take some special action goes here)
return NO;
}
else {
return YES;
}
}
This is a delegate method call, so when I set up the UIWebView, which I do programmatically in the Controller loadView method, I set the WebView's delegate to that same Controller:
myWebView.delegate = self;