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



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

测试应用程序可在https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.zip但我将在下面描述它。

我的测试应用程序(使用序列图板构建,但实际应用程序不使用它们)有两个视图控制器(非原始名称为ViewControllerViewController2)。CCD_ 6包含在作为根视图控制器的CCD_。ViewController包含一个UIWebView(工作正常)、一个"显示"("按下")ViewController2的按钮和一个模式显示ViewController2UIBarButtonItemViewController2有另一个UIWebView,它在"推送"时工作,但在"呈现"时不工作。

ViewControllerViewController2都加载了:

- (void)viewDidLoad {
  [super viewDidLoad];
  [self.webView loadHTMLString:@"<input type="file" accept="image/*;capture=camera">" baseURL:nil];
}

当尝试使用模式UIWebView时,Xcode在控制台中打印以下内容并解除应用程序模式:

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

我目前的理论是,UIActionSheetUIAlertController的变化可能产生了这种情况,但很难证明。我会在苹果公司开一个雷达,以防万一。

是否有人发现了同样的情况和解决方法?

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

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

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

检查是否存在presentViewController似乎可以工作。

但需要检查的副作用

#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

我在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];
}

这对我来说很好

对我来说,我倾向于有一个自定义的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
    }
}

这意味着你可以有大量的带有web视图的视图控制器,它们都可以使用文件上传元素。

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

我不确定苹果为什么选择不支持这个重要的html元素,但我相信他们有自己的理由。(尽管这个元素在IOS上的Safari上运行得很好。)

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

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

好吧,这是我最终使用的解决方法。这是一个2分钟的更改,非常棘手,但如预期的那样工作,避免了我们都有的错误。基本上,我不是以模式显示子视图控制器,而是将其设置为窗口的rootViewController,并保留对父控制器的引用。所以我以前在哪里有这个(在父视图控制器中):

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

我现在有这个

view.window?.rootViewController = newController

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

newController.delegate = self

最后,在我关闭模态的委托回调中,我曾经有这样的地方:

dismissViewControllerAnimated(true, completion: nil)

我现在有了这个:

viewController.view.window?.rootViewController = self

因此,我们得到的效果与视图控制器完全接管屏幕,然后在完成时放弃控制相同。不过,在这种情况下,它没有设置动画。我有一种感觉,用一些内置的视图动画制作控制器过渡的动画不会很难。

根据苹果公司的建议,希望您已经在使用委托模式来管理与模态控制器的通信,但如果您没有,我相信您可以使用任何数量的方法来保留引用并被调用。

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

我对动画的建议:

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

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

每次视图控制器更改时,我所做的是在root中转换目标视图。

从第一视图控制器:

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

这就是我如何把根传给另一个,当我回到第一个根时,我做到了这一点。

从web视图控制器:

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

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

我不知道这是否是一个好的做法,但在模拟器和设备中效果良好。

希望能有所帮助。

最新更新