开发者

iPad UIWebView position a UIPopoverController view at a href link coords

I'm hoping that this question isn't a stupid one but how does one go about positioning a UIPopoverController view over a UIWebView so that the popup view arrow points at the UIWebView link that was clicked to show it?

I'm using the delegate method;

-(BOOL) webView:(UIWebView *)inWeb shouldStartLoadWithRequest:(NSURLRequest *)inRequest navigationType:(UIWebViewNavigationType)inType {
if ( [[[inRequest URL] absoluteString] hasPrefix:@"myscheme:"] ) {
//UIPopoverController stuff here
return NO;
}

}

to capture and route the click but I'm unsure how to get the link coords to position the popup view.

Any help or pointer to relevant info wou开发者_StackOverflow社区ld be very much appreciated.


I have a solution that works but I think there is a better way to do it.

I created a TouchableWebView that inherits from UIWebView and the save the touch position in the method hitTest. After that, you need to set a delegate for your webview and implement the method -webView:shouldStartLoadWithRequest:navigationType:

TouchableWebView.h :

@interface TouchableWebView : UIWebView {
CGPoint lastTouchPosition;
}
@property (nonatomic, assign) CGPoint lastTouchPosition;

TouchableWebView.m :

// I need to retrieve the touch position in order to position the popover
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    self.lastTouchPosition = point;
    return [super hitTest:point withEvent:event];
}

In RootViewController.m :

[self.touchableWebView setDelegate:self];

// WebView delegate, when hyperlink clicked
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request     navigationType:(UIWebViewNavigationType)navigationType {

    if (navigationType == UIWebViewNavigationTypeLinkClicked) 
    {   
        CGPoint touchPosition = [self.view convertPoint:self.touchableWebView.lastTouchPosition fromView:self.touchableWebView];
        [self displayPopOver:request atPosition:touchPosition isOnCelebrityFrame:FALSE];
        return FALSE;
    }

    return TRUE;
}

It's not good because documentation of UIWebView says that you shouldn't subclass it. I guess there is a nicer way but this does work. Did you find another solution ?


Give each link a unique ID and pass that ID to your Obj-C code via your "myscheme:" logic.

You can then determine the link's left & top offset in the UIWebView via Javascript calls:

NSString *leftJS = [NSString stringWithFormat:@"document.getElementById('%d').offsetLeft - scrollX", linkID];
NSInteger leftOffset = [[currentTextView stringByEvaluatingJavaScriptFromString:js] intValue];

NSString *topJS = [NSString stringWithFormat:@"document.getElementById('%d').offsetTop - scrollY", linkID];
NSInteger topOffset = [[currentTextView stringByEvaluatingJavaScriptFromString:js] intValue];

Subtracting scrollX/scrollY accounts for how much to the left or down the user has scrolled the UIWebView.

My understanding is that offsetLeft and offsetTop return the offsets of the element within its parent. So hopefully your links are at the top of the hierarchy instead of embedded in divs or else determining the offset gets more complicated.


For me, use of getBoundingClientRect() and convert it to CGRect works great.

NSString *js = [NSString stringWithFormat:@"JSON.stringify($(\"a[href='%@']\")[0].getBoundingClientRect())", [inRequest URL]];                                                                          
// {top:, right:, bottom:, left:, width:, height:}
NSString *rectJson =  [webView stringByEvaluatingJavaScriptFromString:js];                                                                                                                       
NSError *error = nil;                                                                                                                                                                            
NSDictionary *rectDict = [NSJSONSerialization JSONObjectWithData:[rectJson dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&error];                         
if (error) {
    NSLog(@"json deserialization failed: %@\n%@", rectJson, error);                                                                                                                              
}
CGRect rect = CGRectMake([rectDict[@"left"] floatValue], [rectDict[@"top"] floatValue], [rectDict[@"width"] floatValue], [rectDict[@"height"] floatValue]);                                      
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜