我发现,在为iOS 8编译(并在iOS 8中运行)时,如果UIWebView
位于模式显示的视图控制器中,则UIWebView
无法显示相机/图像选择器。它在直接从窗口rootViewController
"挂起"的视图控制器或从窗口推送的视图控制器中工作时没有问题
测试应用程序可在https://dl.dropboxusercontent.com/u/6214425/TestModalWebCamera.zip但我将在下面描述它。
我的测试应用程序(使用序列图板构建,但实际应用程序不使用它们)有两个视图控制器(非原始名称为ViewController
和ViewController2
)。CCD_ 6包含在作为根视图控制器的CCD_。ViewController
包含一个UIWebView
(工作正常)、一个"显示"("按下")ViewController2
的按钮和一个模式显示ViewController2
的UIBarButtonItem
。ViewController2
有另一个UIWebView
,它在"推送"时工作,但在"呈现"时不工作。
ViewController
和ViewController2
都加载了:
- (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!
我目前的理论是,UIActionSheet
到UIAlertController
的变化可能产生了这种情况,但很难证明。我会在苹果公司开一个雷达,以防万一。
是否有人发现了同样的情况和解决方法?
我发现在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)
一切都很好,我可以显示从库中选择照片、拍照和其他一切的模式。
我不知道这是否是一个好的做法,但在模拟器和设备中效果良好。
希望能有所帮助。