本文介绍了UIWebView - 在< img>上启用动作表标签的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

仅仅是我还是在UIWebView中禁用了< img> 标签上的操作表?在Safari中,例如,当您想要在本地保存图像时,触摸并按住图像以显示操作表。但它不能在我的自定义UIWebView中工作。我的意思是,它仍然适用于< a> 标签,即,当我触摸并按住html链接时,会显示一个操作表。但不适用于< img> 标记。

Is it just me or has the action sheet on <img> tags been disabled in UIWebView? In Safari, e.g, when you want to save an image locally, you touch and hold on the image to get an action sheet shown. But it's not working in my custom UIWebView. I mean, it is still working for <a> tags, i.e, when I touch and hold on html links, an action sheet shows up. But not for the <img> tags.

我尝试过像 img {-webkit-touch-callout:inherit;在css中的,它不起作用。另一方面,当我双击并按住图像时,会出现一个复制气球。

I've tried things like putting img { -webkit-touch-callout: inherit; } in css, which didn't work. On the other hand, when I double-tap and hold on the images, a copy-balloon shows up.

所以问题是,是否为UIWebView禁用了< img> 标签的默认操作表标注?是这样,有没有办法重新启用它?我已经google了一下,看到很多Q& As关于如何在UIWebView中禁用它,所以只是我没有看到弹出窗口?

So the question is, has the default action sheet callout for <img> tags been disabled for UIWebView? Is so, is there a way to re-enable it? I've googled around and saw many Q&As on how to disable it in UIWebView, so is it just me who aren't seeing the popup?

提前致谢!

推荐答案

是的,Apple已禁用此功能(以及其他)在UIWebViews中保留它仅用于Safari。

Yes apple has disabled this feature (among others) in UIWebViews and kept it for Safari only.

但是你可以通过扩展本教程来自己重新创建它,。

However you can recreate this yourself by extending this tutorial, http://www.icab.de/blog/2010/07/11/customize-the-contextual-menu-of-uiwebview/.

完成本教程后,您需要添加一些额外的内容,以便实际保存图像(教程没有涵盖)。
我在0.3秒后添加了一个名为@tapAndHoldShortNotification的额外通知,它调用了一个只带有禁用标注代码的方法(以防止在页面仍然加载时默认和你自己的菜单弹出,一个小bug修复)。

Once you've finished this tutorial you'll want to add a few extra's so you can actually save images (which the tutorial doesn't cover).I added an extra notification called @"tapAndHoldShortNotification" after 0.3 seconds which calls a method with just the disable callout code in it (to prevent both the default and your own menu popping while the page is still loading, a little bug fix).

另外,为了检测你需要扩展JSTools.js的图像,这里有我的额外功能。

Also to detect images you'll need to extend the JSTools.js, here's mine with the extra functions.

function MyAppGetHTMLElementsAtPoint(x,y) {
    var tags = ",";
    var e = document.elementFromPoint(x,y);
    while (e) {
        if (e.tagName) {
            tags += e.tagName + ',';
        }
        e = e.parentNode;
    }
    return tags;
}

function MyAppGetLinkSRCAtPoint(x,y) {
    var tags = "";
    var e = document.elementFromPoint(x,y);
    while (e) {
        if (e.src) {
            tags += e.src;
            break;
        }
        e = e.parentNode;
    }
    return tags;
}

function MyAppGetLinkHREFAtPoint(x,y) {
    var tags = "";
    var e = document.elementFromPoint(x,y);
    while (e) {
        if (e.href) {
            tags += e.href;
            break;
        }
        e = e.parentNode;
    }
    return tags;
}

现在你可以检测用户点击图像并实际查找图像网址他们点击了,但是我们需要更改 - (void)openContextualMenuAtPoint:方法以提供额外的选项。

Now you can detect the user clicking on images and actually find out the images url they are clicking on, but we need to change the -(void)openContextualMenuAtPoint: method to provide extra options.

再次这里是我的(我试图复制Safari的行为):

Again here's mine (I tried to copy Safari's behaviour for this):

- (void)openContextualMenuAt:(CGPoint)pt{
    // Load the JavaScript code from the Resources and inject it into the web page
    NSString *path = [[NSBundle mainBundle] pathForResource:@"JSTools" ofType:@"js"];
    NSString *jsCode = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    [webView stringByEvaluatingJavaScriptFromString:jsCode];

    // get the Tags at the touch location
    NSString *tags = [webView stringByEvaluatingJavaScriptFromString:
                      [NSString stringWithFormat:@"MyAppGetHTMLElementsAtPoint(%i,%i);",(NSInteger)pt.x,(NSInteger)pt.y]];

    NSString *tagsHREF = [webView stringByEvaluatingJavaScriptFromString:
                          [NSString stringWithFormat:@"MyAppGetLinkHREFAtPoint(%i,%i);",(NSInteger)pt.x,(NSInteger)pt.y]];

    NSString *tagsSRC = [webView stringByEvaluatingJavaScriptFromString:
                         [NSString stringWithFormat:@"MyAppGetLinkSRCAtPoint(%i,%i);",(NSInteger)pt.x,(NSInteger)pt.y]];



    UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];

    selectedLinkURL = @"";
    selectedImageURL = @"";

    // If an image was touched, add image-related buttons.
    if ([tags rangeOfString:@",IMG,"].location != NSNotFound) {
        selectedImageURL = tagsSRC;

        if (sheet.title == nil) {
            sheet.title = tagsSRC;
        }

        [sheet addButtonWithTitle:@"Save Image"];
        [sheet addButtonWithTitle:@"Copy Image"];
    }
    // If a link is pressed add image buttons.
    if ([tags rangeOfString:@",A,"].location != NSNotFound){
        selectedLinkURL = tagsHREF;

        sheet.title = tagsHREF;
        [sheet addButtonWithTitle:@"Open"];
        [sheet addButtonWithTitle:@"Copy"];
    }

    if (sheet.numberOfButtons > 0) {
        [sheet addButtonWithTitle:@"Cancel"];
        sheet.cancelButtonIndex = (sheet.numberOfButtons-1);
        [sheet showInView:webView];
    }
    [selectedLinkURL retain];
    [selectedImageURL retain];
    [sheet release];
}

(注意:selectedLinkURL和selectedImageURL在.h文件中声明让他们可以在整个班级访问,以保存或打开后者的链接。

(NOTES: selectedLinkURL and selectedImageURL are declared in the .h file to let them be accessed throughout the class, for saving or opening the link latter.

到目前为止,我们刚刚回过教程代码进行更改,但现在我们将进入本教程未涵盖的内容(在实际提及如何处理保存图像或打开链接之前停止)。

So far we've just been going back over the tutorials code making changes but now we will move into what the tutorial doesn't cover (it stops before actually mentioning how to handle saving the images or opening the links).

要处理用户选择,我们现在需要添加actionSheet:clickedButtonAtIndex:方法。

To handle the users choice we now need to add the actionSheet:clickedButtonAtIndex: method.

-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
    if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:@"Open"]){
        [webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:selectedLinkURL]]];
    }
    else if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:@"Copy"]){
        [[UIPasteboard generalPasteboard] setString:selectedLinkURL];
    }
    else if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:@"Copy Image"]){
        [[UIPasteboard generalPasteboard] setString:selectedImageURL];
    }
    else if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:@"Save Image"]){
        NSOperationQueue *queue = [NSOperationQueue new];
        NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(saveImageURL:) object:selectedImageURL];
        [queue addOperation:operation];
        [operation release];
    }
}

这会检查用户想要做什么和处理/大多数/它们,只有保存图像操作需要另一种方法来处理它。为了进步,我使用了MBProgressHub。
添加MBProgressHUB * progressHud;到.h中的接口声明并在init方法中设置它(你处理webview的任何类)。

This checks what the user wants to do and handles /most/ of them, only the "save image" operation needs another method to handle that. For the progress I used MBProgressHub.Add an MBProgressHUB *progressHud; to the interface declaration in the .h and set it up in the init method (of whatever class you're handling the webview from).

    progressHud = [[MBProgressHUD alloc] initWithView:self.view];
    progressHud.customView = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Tick.png"]] autorelease];
    progressHud.opacity = 0.8;
    [self.view addSubview:progressHud];
    [progressHud hide:NO];
    progressHud.userInteractionEnabled = NO;

和 - (void)saveImageURL:(NSString *)url;方法实际上将它保存到图像库。
(一种更好的方法是通过NSURLRequest进行下载并更新MBProgressHUDModeDeterminate中的进度hud,以转移它实际需要多长时间下载,但这是一个更加黑客攻击的实现然后那个)

And the -(void)saveImageURL:(NSString*)url; method will actually save it to the image library.(A better way would be to do the download through an NSURLRequest and update the progress hud in MBProgressHUDModeDeterminate to deflect how long it'll actually take to download, but this is a more hacked together implementation then that)

-(void)saveImageURL:(NSString*)url{
    [self performSelectorOnMainThread:@selector(showStartSaveAlert) withObject:nil waitUntilDone:YES];
    UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]], nil, nil, nil);
    [self performSelectorOnMainThread:@selector(showFinishedSaveAlert) withObject:nil waitUntilDone:YES];
}
-(void)showStartSaveAlert{
    progressHud.mode = MBProgressHUDModeIndeterminate;
    progressHud.labelText = @"Saving Image...";
    [progressHud show:YES];
}
-(void)showFinishedSaveAlert{
    // Set custom view mode
    progressHud.mode = MBProgressHUDModeCustomView;
    progressHud.labelText = @"Completed";
    [progressHud performSelector:@selector(hide:) withObject:[NSNumber numberWithBool:YES] afterDelay:0.5];
}

原因是添加[progressHud release];到dealloc方法。

And of cause add [progressHud release]; to the dealloc method.

希望这能告诉你如何将一些选项添加到苹果遗漏的webView中。
原因虽然您可以为此添加更多内容,例如instapaper的Read Later选项或在Safari中打开按钮。
(看看这篇文章的长度,我看到为什么原始教程遗漏了最终的实施细节)

Hopefully this shows you how to add some of the options to a webView that apple left out.Of cause though you can add more things to this like a "Read Later" option for instapaper or a "Open In Safari" button.(looking at the length of this post I'm seeing why the original tutorial left out the finial implementation details)

(更新时间:更多信息)

我被问及我在顶部隐藏的细节,@tapAndHoldShortNotification,所以这是澄清它。

I was asked about the detail I glossed over at the top, the @"tapAndHoldShortNotification", so this is clarifying it.

这是我的UIWindow子类,它添加了第二个通知来取消默认选择菜单(这是因为当我尝试教程时它显示了两个菜单)。

This is my UIWindow subclass, it adds the second notification to cancel the default selection menu (this is because when I tried the tutorial it showed both menus).

- (void)tapAndHoldAction:(NSTimer*)timer {
    contextualMenuTimer = nil;
    UIView* clickedView = [self hitTest:CGPointMake(tapLocation.x, tapLocation.y) withEvent:nil];
    while (clickedView != nil) {
        if ([clickedView isKindOfClass:[UIWebView class]]) {
            break;
        }
        clickedView = clickedView.superview;
    }

    if (clickedView) {
        NSDictionary *coord = [NSDictionary dictionaryWithObjectsAndKeys:
                               [NSNumber numberWithFloat:tapLocation.x],@"x",
                               [NSNumber numberWithFloat:tapLocation.y],@"y",nil];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"TapAndHoldNotification" object:coord];
    }
}
- (void)tapAndHoldActionShort:(NSTimer*)timer {
    UIView* clickedView = [self hitTest:CGPointMake(tapLocation.x, tapLocation.y) withEvent:nil];
    while (clickedView != nil) {
        if ([clickedView isKindOfClass:[UIWebView class]]) {
            break;
        }
        clickedView = clickedView.superview;
    }

    if (clickedView) {
        NSDictionary *coord = [NSDictionary dictionaryWithObjectsAndKeys:
                               [NSNumber numberWithFloat:tapLocation.x],@"x",
                               [NSNumber numberWithFloat:tapLocation.y],@"y",nil];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"TapAndHoldShortNotification" object:coord];
    }
}

- (void)sendEvent:(UIEvent *)event {
    NSSet *touches = [event touchesForWindow:self];
    [touches retain];

    [super sendEvent:event];    // Call super to make sure the event is processed as usual

    if ([touches count] == 1) { // We're only interested in one-finger events
        UITouch *touch = [touches anyObject];

        switch ([touch phase]) {
            case UITouchPhaseBegan:  // A finger touched the screen
                tapLocation = [touch locationInView:self];
                [contextualMenuTimer invalidate];
                contextualMenuTimer = [NSTimer scheduledTimerWithTimeInterval:0.8 target:self selector:@selector(tapAndHoldAction:) userInfo:nil repeats:NO];
                NSTimer *myTimer;
                myTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(tapAndHoldActionShort:) userInfo:nil repeats:NO];
                break;

            case UITouchPhaseEnded:
            case UITouchPhaseMoved:
            case UITouchPhaseCancelled:
                [contextualMenuTimer invalidate];
                contextualMenuTimer = nil;
                break;
        }
    } else {        // Multiple fingers are touching the screen
        [contextualMenuTimer invalidate];
        contextualMenuTimer = nil;
    }
    [touches release];
}

然后按如下方式处理通知:

The notification is then handled like this:

// in -viewDidLoad

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(stopSelection:) name:@"TapAndHoldShortNotification" object:nil];


- (void)stopSelection:(NSNotification*)notification{
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
}

这只是一个小小的变化,但它修复了烦人的小虫子,你得到2菜单出现(标准的和你的)。

It's only a little change but it fixes the annoying little bug where you get 2 menus appear (the standard one and yours).

此外,您可以通过在通知触发时发送触摸位置,然后从该点显示UIActionSheet,轻松添加iPad支持,虽然这是在iPad之前写的,所以不包括对它的支持。

Also you could easily add iPad support by sending the touches location as the notification fires and then showing the UIActionSheet from that point, though this was written before the iPad so doesn't include support for that.

这篇关于UIWebView - 在&lt; img&gt;上启用动作表标签的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-12 09:54