相机覆盖视图 - 仅用于预览?

15

我注意到在OS 3.1中,您可以使用

overlay

视图将覆盖层添加到图像选择器中。

cameraOverlayView
然而,我也注意到使用这种方法添加视图时,在整个UIImagePicker显示期间也会显示该视图,但我只想在预览阶段显示它。 有没有办法只在预览阶段发生这种情况? 我不希望在打开快门动画或询问是否要使用图像或重新拍摄的屏幕中出现它。

2
嘿,mac_55!只是想温柔地提醒您接受/评论我的更新答案。 - Ivan Karpan
4个回答

19

我只是想展示一种无需操作子视图的可能性。 在CameraPicker中,存在用于通知系统更改的通知。它们也没有被记录下来(就像子视图结构一样)。因此,它们也可能会发生变化,但你可以接收到这些通知。

你可以使用无名称注册它们:

[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(notificationReceived:) name: nil object: nil];

我们在这里获得一些有趣的(自我解释的)通知:

PLCameraControllerPreviewStartedNotification
PLCameraViewIrisAnimationWillBeginNotification
PLCameraViewIrisAnimationDidEndNotification

Recorder_DidStartPreviewing
Recorder_SourceStarted
Recorder_WillCapturePhoto
Recorder_DidCapturePhoto
Recorder_PhotoStillImageSampleBufferReady
Recorder_DidStopPreviewing

_UIImagePickerControllerUserDidCaptureItem // Photo was taken, preview is shown
_UIImagePickerControllerUserDidRejectItem  // Repeat was pressed, camera is shown again 
您可以使用它们来触发您的覆盖视图的隐藏状态或其他任何操作。

你认为使用这些东西会导致你的应用被拒绝吗? - Javier Soto
不,这些只是字符串。这应该可以工作。但我还没有测试过。 - calimarkus
1
经过测试,我成功地通过依附于“_UIImagePickerControllerUserDidCaptureItem”通知来改变我的预览视图与相机视图不同。 我注意到,在iOS 6中,既没有PLCameraViewIrisAnimationWillBeginNotification通知,也没有PLCameraViewIrisAnimationDidEndNotification通知被触发,因此我必须通过使用那些事件周围的通知来解决问题,例如“Recorder_WillCapturePhoto”和“PLCameraControllerPreviewStartedNotification”。 - Christian
这还能用吗?我好像无法让它正常工作。 - joshLor

18

我已经想出了一种方法让你实现所需的结果,虽然有点……不太标准。:)

这个想法是稍微重新排列 UIImagePickerController 使用的内部视图顺序。

好的,我们创建一个 UIImagePickerController 对象,初始化它并添加一个叠加视图。请注意!这个 UIView 对象(在示例代码中为 UIImageView)从一开始就被隐藏了。千万别错过。最后,我们将图像选择器控制器呈现为模态视图控制器。这段代码应该放在你的 applicationDidFinishLaunching:viewWillAppear: 或类似的适当即将启动的方法中。

UIImagePickerController *anImagePickerController = [UIImagePickerController new];
anImagePickerController.delegate = self;
anImagePickerController.sourceType = UIImagePickerControllerSourceTypeCamera;

UIImageView *anImageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Watermark.png"]];
anImageView.frame = CGRectMake(0, 1, anImageView.image.size.width, anImageView.image.size.height);
anImageView.hidden = YES;
anImagePickerController.cameraOverlayView = anImageView;

[viewController presentModalViewController:anImagePickerController animated:NO];
[anImagePickerController release];

[NSTimer scheduledTimerWithTimeInterval:0.1
                                 target:self
                               selector:@selector(timerFireMethod:)
                               userInfo:anImageView
                                repeats:YES];
[anImageView release];

在遮盖视图 (anImageView) 被释放之前,创建了一个 NSTimer,并用 anImageView (NSTimeruserInfo 属性) 进行初始化,并立即安排定时器。下面是它调用的方法:

- (void)timerFireMethod:(NSTimer*)theTimer {
    UIView *cameraOverlayView = (UIView *)theTimer.userInfo;
    UIView *previewView = cameraOverlayView.superview.superview;

    if (previewView != nil) {
        [cameraOverlayView removeFromSuperview];
        [previewView insertSubview:cameraOverlayView atIndex:1];

        cameraOverlayView.hidden = NO;

        [theTimer invalidate];
    }
}

整个NSTimer的过程被添加到流程中,以确保重新排序解决方法恰好在UIImagePickerController完全准备好时发生。

就是这样。它很有效,虽然不是标准的,但简单粗暴。再次请随意优化并使其更加正确(哦,请务必这样做,我的目的是为了向您展示该方法)。


我在考虑设置视图在计时器运行后显示,但是我不确定相机加载所需的时间是否总是相同的 - 这不取决于使用的内存量以及它运行的设备吗?例如,在3GS上加载速度比3G快。 - mac_55
嘿mac_55,我已经优化了我的解决方案 - 现在它完美无缺(尽可能完美地解决了问题)。 :) 希望有所帮助。 - Ivan Karpan
抱歉耽搁了。我还没有抽出时间来测试这个,但我很乐意将其标记为答案。 :) - mac_55
真的,你只需要使用NotificationCenter...这是一行代码。https://dev59.com/SmMm5IYBdhLWcg3wBrXD - Fattie

6
实际上,我也在尝试同样的事情,通过这篇博客文章我找到了一个更简单的方法:http://www.alexcurylo.com/blog/2009/06/18/uiimagepickercontroller-in-3-0/ 由于UIImagePickerController可以调用UINavigatorControllerDelegate,因此下面的方法会在显示图像选择器之前被调用。
以下是重要的代码:
 - (void)navigationController:(UINavigationController *)navigationController
willShowViewController:(UIViewController *)viewController
animated:(BOOL)animated
{
   if (!viewController)
   return;

   UIView* controllerViewHolder = viewController.view;
   UIView* controllerCameraView = [[controllerViewHolder subviews] objectAtIndex:0];
   UIView* controllerPreview = [[controllerCameraView subviews] objectAtIndex:0];
   [controllerCameraView insertSubview:self.overlayView aboveSubview:controllerPreview];
}

希望这有所帮助。

-2

当您构建选择器时,请将覆盖层添加到选择器中(picker.cameraOverlayView = myView)。

覆盖层不会出现在拍摄的照片中。它只是一个覆盖视图,就像它所说的那样。

您可以在拍照之前(takePicture方法)删除覆盖视图,并在imagePickerController:didFinishPickingMediaWithInfo:中再次添加视图。


抱歉,这不是我要找的。我想在拍照之前仅显示叠加层。而不是在相机快门动画期间或询问您是否喜欢所拍照片时显示。 - mac_55
如果在调用takePicture之前移除覆盖物 (picker.cameraOverlayView = nil),则当快门动画时覆盖物将不会存在。 - diederikh
但是我该如何在预览屏幕上显示它呢?我正确地认为takePhoto捕获预览屏幕上的任何内容吗?但是我想在预览屏幕上显示覆盖层(在拍照之前)困惑 - mac_55
我觉得你误解了我的意图。我知道叠加层不包含在拍摄的图片中,但它在整个捕捉过程中都显示在屏幕上 - 我不希望它在所有这段时间都显示在屏幕上,只想让它在用户看到“拍照”按钮的屏幕上显示。 - mac_55

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接