iOS 8 SDK:模态 UIWebView 和相机/图像选择器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25942676/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 02:38:51  来源:igfitidea点击:

iOS 8 SDK: modal UIWebView and camera/image picker

iosobjective-cios8uiwebviewuiimagepickercontroller

提问by yonosoytu

I have found that, when compiling for iOS 8 (and running in iOS 8), a UIWebViewcannot show the camera/image picker if the UIWebViewis in a view controller presented modally. It works without problem in view controllers directly “hanging” from the window rootViewControlleror view controllers pushed from it.

我发现,在为 iOS 8 编译(并在 iOS 8 中运行)时,UIWebView如果UIWebViewa 在以模态呈现的视图控制器中,则无法显示相机/图像选择器。它在视图控制器直接从窗口“挂起”rootViewController或从窗口推送的视图控制器中没有问题。

The test application can be found at https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.zipbut I will describe it below.

测试应用程序可以在https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.zip找到,但我将在下面进行描述。

My test application (built with storyboards, but the real application doesn't use them) has two view controllers (unoriginally named ViewControllerand ViewController2). ViewControlleris contained in a UINavigationControllerwhich is the root view controller. ViewControllercontains a UIWebView(works OK), a button that “shows” (“pushes”) ViewController2, and a UIBarButtonItemwhich modally presents ViewController2. ViewController2has another UIWebViewwhich works when “pushed” but not when “presented”.

我的测试应用程序(用故事板构建,但实际应用程序不使用它们)有两个视图控制器(非原始命名的ViewControllerViewController2)。ViewController包含在UINavigationController根视图控制器 a 中。ViewController包含一个UIWebView(工作正常),一个“显示”(“推”)的按钮ViewController2,以及一个UIBarButtonItem模态呈现的按钮ViewController2ViewController2有另一个UIWebView在“推动”时有效,但在“呈现”时无效。

Both ViewControllerand ViewController2are loaded with:

双方ViewControllerViewController2装载有:

- (void)viewDidLoad {
  [super viewDidLoad];

  [self.webView loadHTMLString:@"<input type=\"file\" accept=\"image/*;capture=camera\">" baseURL:nil];
}

When trying to use the modal UIWebViewXcode prints the following in the console and dismisses the app modal:

尝试使用模式时,UIWebViewXcode 会在控制台中打印以下内容并关闭应用模式:

Warning: Attempt to present <UIImagePickerController: 0x150ab800> on <ViewController2: 0x14623580> whose view is not in the window hierarchy!

My current theory is that the changes in UIActionSheetto UIAlertControllermight have produced this situation, but it's quite hard to prove. I will open a Radar with Apple, just in case.

我目前的理论是UIActionSheetto的变化UIAlertController可能会产生这种情况,但很难证明。以防万一,我会用苹果打开一个雷达。

Has someone found the same situation and some workaround?

有人发现了相同的情况和一些解决方法吗?

回答by seeinvisible

I found that in iOS 8.0.2 iPad does not seem to have that bug but iPhone still does.

我发现在 iOS 8.0.2 中 iPad 似乎没有那个错误,但 iPhone 仍然有。

However, overriding following in the view controller containing the uiwebview

但是,在包含 uiwebview 的视图控制器中覆盖以下内容

-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion

And checking that there is a presentedViewController seems to work.

并检查是否有一个presentedViewController 似乎工作。

But need to check side effects

但需要检查副作用

#import "UiWebViewVC.h"

@interface UiWebViewVC ()

@property (weak, nonatomic) IBOutlet UIWebView *uiwebview;

@end

@implementation UiWebViewVC

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSURL *url = [NSURL URLWithString:@"http://html5demos.com/file-api-simple"];

    NSURLRequest *request = [NSURLRequest requestWithURL:url];

    self.uiwebview.scalesPageToFit = YES;

    [self.uiwebview loadRequest:request];
}


-(void)dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion
{
    if ( self.presentedViewController)
    {
        [super dismissViewControllerAnimated:flag completion:completion];
    }
}


@end

回答by Artyom Devyatov

I have the same issue on iOS 9. Try to add ivar '_flag' and then override this methods in view controller with UIWebView

我在 iOS 9 上有同样的问题。尝试添加 ivar '_flag',然后使用 UIWebView 在视图控制器中覆盖此方法

#pragma mark - Avoiding iOS bug

- (UIViewController *)presentingViewController {

    // Avoiding iOS bug. UIWebView with file input doesn't work in modal view controller

    if (_flagged) {
        return nil;
    } else {
       return [super presentingViewController];
    }
}

- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion {

    // Avoiding iOS bug. UIWebView with file input doesn't work in modal view controller

    if ([viewControllerToPresent isKindOfClass:[UIDocumentMenuViewController class]]
    ||[viewControllerToPresent isKindOfClass:[UIImagePickerController class]]) {
        _flagged = YES;
    }

    [super presentViewController:viewControllerToPresent animated:flag completion:completion];
}

- (void)trueDismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {

    // Avoiding iOS bug. UIWebView with file input doesn't work in modal view controller

    _flagged = NO;
    [self dismissViewControllerAnimated:flag completion:completion];
}

This works for me fine

这对我有用

回答by Jeremy JC Paul

For me I tend to have a custom UINavigationController so that multiple views can share the same logic. So for my workaround (in Swift) here is what I put in my custom NavigationController.

对我来说,我倾向于使用自定义 UINavigationController 以便多个视图可以共享相同的逻辑。因此,对于我的解决方法(在 Swift 中),这是我在自定义 NavigationController 中放入的内容。

import UIKit

class NavigationController: UINavigationController {

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    override func dismissViewControllerAnimated(flag: Bool, completion: (() -> Void)?) {
        if let vc = self.presentedViewController {
            // don't bother dismissing if the view controller being presented is a doc/image picker
            if !vc.isKindOfClass(UIDocumentMenuViewController) || !vc.isKindOfClass(UIImagePickerController) {
                super.dismissViewControllerAnimated(flag, completion:completion)
            }
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // make sure that the navigation controller can't be dismissed
        self.view.window?.rootViewController = self
    }
}

This means that you can have loads of view controllers with webviews and they'll all work with the file upload element.

这意味着您可以拥有大量带有 webview 的视图控制器,并且它们都可以与文件上传元素一起使用。

回答by Takide

I was having a similar issue, and I have discovered that the UIWebView elements in IOS do not support the html element:

我遇到了类似的问题,我发现 IOS 中的 UIWebView 元素不支持 html 元素:

I am not sure why Apple chose to not support this IMPORTANT html element, but I am sure they have their reasons. (Even though this element works perfectly on Safari on IOS.)

我不知道为什么 Apple 选择不支持这个重要的 html 元素,但我相信他们有他们的理由。(即使这个元素在 IOS 上的 Safari 上也能完美运行。)

In many cases, when the user clicks this kind of button in a UIWebView, it will let them take/ choose a photo. HOWEVER, the UIWebView in IOS does not have the capability to attach files like this into the POST data when the form is submitted.

在很多情况下,当用户在 UIWebView 中点击这种按钮时,它会让他们拍摄/选择一张照片。但是,IOS 中的 UIWebView 没有能力在提交表单时将这样的文件附加到 POST 数据中。

The Solution: To accomplish the same task you can create a similar form in InterfaceBuilder with a button that triggers the UIImagePickerController. Then, you create you an HTTP POST request with all of the form data and the image. It isn't as hard as it sounds, check out the link below for some sample code that gets the job done: ios Upload Image and Text using HTTP POST

解决方案:要完成相同的任务,您可以在 InterfaceBuilder 中创建一个类似的表单,其中包含一个触发 UIImagePickerController 的按钮。然后,您创建一个包含所有表单数据和图像的 HTTP POST 请求。这并不像听起来那么难,请查看下面的链接以获取一些完成工作的示例代码:ios 使用 HTTP POST 上传图像和文本

回答by kelin

My solution is to create custom View Controller with custom modal presentation based on controllers child-parent hierarchy. Animation will be the same so the user will not notice the difference.

我的解决方案是基于控制器子父层次结构创建具有自定义模式演示的自定义视图控制器。动画将是相同的,因此用户不会注意到差异。

My suggestions for animation:

我对动画的建议:

animateWithDuration:(animated ? 0.6 : 0.0)
                      delay:0.0
     usingSpringWithDamping:1.f
      initialSpringVelocity:0.6f
                    options:UIViewAnimationOptionCurveEaseOut

It will look exactly like default modal presentation animation in iOS7/8.

它看起来与 iOS7/8 中的默认模态演示动画完全一样。

回答by bloudermilk

Alright, here's the workaround I ended up using. It's a 2 minute change, pretty hacky, but works as expected and avoids the bug we're all having. Basically, rather than presenting the child view controller modally, I set it to the window's rootViewController and keep a reference to the parent controller. So where I used to have this (in parent view controller):

好的,这是我最终使用的解决方法。这是一个 2 分钟的更改,相当笨拙,但按预期工作并避免了我们都遇到的错误。基本上,我没有以模态方式呈现子视图控制器,而是将其设置为窗口的 rootViewController 并保留对父控制器的引用。所以我曾经有这个(在父视图控制器中):

presentViewController(newController, animated: true, completion: nil)

I now have this

我现在有这个

view.window?.rootViewController = newController

In both cases, the parent controller is newController's delegate, which is how I keep the reference.

在这两种情况下,父控制器都是newController的委托,这就是我保留引用的方式。

newController.delegate = self

Finally, where in my delegate callback for closing the modal, where I used to have this:

最后,在我的委托回调中关闭模态的位置,我曾经有这个:

dismissViewControllerAnimated(true, completion: nil)

I now have this:

我现在有这个:

viewController.view.window?.rootViewController = self

So we get the same effect of a view controller taking over the screen entirely, then yielding its control when it's done. In this case though, it's not animated. I have a feeling animating the controller transition wouldn't be very hard with some of the built in view animations.

所以我们得到了一个视图控制器完全接管屏幕的相同效果,然后在完成时让出它的控制权。但在这种情况下,它没有动画。我有一种感觉,使用一些内置的视图动画来为控制器过渡设置动画不会很困难。

Hopefully you're already using the delegate pattern to manage communication with the modal controller, per Apple's recommendation, but if you're not I'm sure you can use any number of methods that keep a reference and get called back.

希望您已经根据 Apple 的建议使用委托模式来管理与模态控制器的通信,但如果您不是,我确定您可以使用任意数量的方法来保持引用并被回调。

回答by Jason Sa

What I did what every time the view controller is change, convert the destination view in root.

每次视图控制器更改时我做了什么,在根目录中转换目标视图。

from first view controller:

从第一个视图控制器:

let web = self.storyboard?.instantiateViewController(withIdentifier:"web") as! UINavigationController

view.window?.rootViewController = web

this is how I pass the root to the other, and when comeback to the first one I made this.

这就是我将根传递给另一个的方式,当回到第一个时我做了这个。

from web view controller:

从网络视图控制器:

let first = self.storyboard?.instantiateViewController(withIdentifier: "reveal") as! SWRevealViewController
    present(first, animated: true, completion: nil)

and everything is fine, I can show the modal for select photo from library, take photo and everything else.

一切都很好,我可以显示从库中选择照片的模式,拍照和其他一切。

I don't know if that is a good practice but works fine in emulator and device.

我不知道这是否是一个好习惯,但在模拟器和设备中运行良好。

Hope it helps.

希望能帮助到你。