camera overlay view - just for preview?

本文提供了一种方法,在iOS相机预览阶段仅显示overlay视图,而不影响打开快门动画和重新拍摄屏幕。通过调整UIImagePickerController内部视图顺序并使用NSTimer触发视图显示,实现overlay视图在预览阶段的精确控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Q:

I've noticed that in OS 3.1 you can add an overlay view to the image picker with

cameraOverlayView

However, I've also noticed that adding a view via this method also displays the view for the entire time the UIImagePicker is displayed, when I only want to show it during the preview stage.

Is there a way to make this only happen during preview? I don't want it to be there during the open shutter animation, or the screen that asks whether you want to use the image or retake.


A1:

I've figured out a way for you to achieve the desired result though it's a bit... not so standard. :)

The idea is to rearrange a bit the order of the inner views in the structure UIImagePickerControlleruses.

OK, so we create an UIImagePickerController object, initialize it and add an overlay view to it. May I have your attention please! The UIView object (UIImageView in the example code) is hidden from the very beginning. Don't miss that. Finally we present the image picker controller as modal view controller. This code should be somewhere in your applicationDidFinishLaunching:,viewWillAppear: or similar appropriate about to launch methods.

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];

Before the overlay view (anImageView) is released a NSTimer is created, initialized withanImageView (NSTimer userInfo property) and scheduled right away. Here's the method it calls:

- (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];
    }
}

The whole NSTimer thing is added to the flow to ensure that the reordering work around will happen exactly when the UIImagePickerController will be totally ready for that.

This is it. It works, it's not standard, it's rough and quick. Again feel free to optimize and make it 'righter' (oh please do, my aim was to show you the way).


A2:

I just wanted to show up another possibility without subview fiddling. There are system notifications for the changes in the CameraPicker. They are not documented either (as the subview structure). So they are also subject to change. BUT you get them.

You can register for them using no name:

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

We get some interesting (selfexplaining) notifications here:

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 

You could use them, to trigger your overlayviews hidden state or anything else.



### 解决方案分析 当链接器发出 `L16 WARNING: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS` 的警告时,这通常意味着某些代码段(如函数或数据段)在程序中未被调用,因此这些段不会参与覆盖过程[^2]。这种情况下,虽然不影响程序运行,但如果希望消除此警告并优化内存使用,可以采取以下措施: #### 方法一:移除未使用的代码段 如果确认某些代码段确实不再需要,则可以直接将其从项目中删除。例如,对于 `?PR?MOTORZHUAN`, `?PR?DS1302_INIT` 这样的未调用段,可以通过检查其功能需求来决定是否完全移除它们。 ```c // 如果不需要 DS1302 初始化功能,直接移除相关实现 void DS1302_Init(void) { // Initialization code removed here } ``` 这种方法适用于那些已经废弃的功能模块[^2]。 --- #### 方法二:通过条件编译保留未使用的代码段 为了保持代码的灵活性,在不实际使用的情况下仍能保留特定功能模块,可以采用条件编译的方式控制这些代码段的编译状态。例如: ```c #define INCLUDE_MOTOR_CONTROL 0 #define INCLUDE_DS1302_SUPPORT 0 #if INCLUDE_MOTOR_CONTROL void MOTOR_ZHUA(void) { // Motor control logic } #endif #if INCLUDE_DS1302_SUPPORT void DS1302_Init(void) { // DS1302 initialization logic } #endif ``` 在这种方式下,只需修改宏定义即可轻松启用或禁用相应功能[^2]。 --- #### 方法三:强制调用未使用的代码段 有时即使某个代码段当前未被显式调用,也可能在未来版本中有潜在用途。此时可通过创建一个虚拟入口点来模拟对其的调用,从而避免链接器忽略它。例如: ```c static void ForceCallUnusedSegments(void) { volatile int dummy; // 假设这些函数可能未来会用到 dummy += MOTOR_ZHUA(); dummy += DS1302_Init(); (void)dummy; // 防止编译器报未使用变量的警告 } int main(void) { ForceCallUnusedSegments(); // 调用虚拟入口点 while (1); } ``` 这种方式能够有效防止链接器因检测不到真实调用而丢弃目标代码段。 --- #### 方法四:调整链接器配置 部分嵌入式开发环境中允许自定义链接脚本或选项以改变默认行为模式。比如设置 `-u` 参数手动指定哪些符号应始终保留下来而不受覆盖率影响;或者重新审视 `.ovl` 文件中的规则确保所有必要片段均得到适当处理[^1]。 > **注意**: 修改链接器参数需谨慎操作以免引发其他不可预见后果! --- ### 总结 针对 `L16 WARNING: UNCALLED SEGMENT, IGNORED FOR OVERLAY PROCESS` 提供了四种解决方案——分别是彻底清除冗余资源、借助预处理器指令灵活管理可用组件、构建人为触发机制维持存在感以及微调工具链属性适应特殊场景需求。具体选用哪一种取决于实际应用场景和个人偏好等因素综合考量之后再做定夺[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值