20180926105746690.jpg
1、如果你需求的页面没有那么复杂,可以继承
UIImagePickerController
对其拍摄页面进行重绘。2、如果是较复杂的拍摄页,则需要完全自定义相机页。关于这个可以参考类似这篇博客
我们今天先来说说第一种。也就是类似我文章头部的这种界面怎么画出来。额~这时候还是给心急的上个Demo吧。在文中,顺便说下我碰到的两个问题:拍摄页灰色透明遮罩绘制
和拍摄后黑屏问题
代码Demo
都有了,我这里只说下流程。
UIImagePickerController
的自定义类。那么,自定义绘制页应该使用到cameraOverlayView
属性。简单来说你可以写一个View
直接赋值给这个属性,就算是自定义拍摄页了。不过我Demo
里面没有这样做,因为我这里拍摄完成要隐藏这个绘制的图层,而使用这个属性你就无法隐藏了。 self.sourceType = UIImagePickerControllerSourceTypeCamera;
//隐藏拍摄工具
self.showsCameraControls = NO;
//预览图
[self.view addSubview:self.preView];
//遮罩区父视图
self.baseView = [[SNFCreditScoreCameraBaseView alloc] initWithFrame:kContentFrame];
[self.view addSubview:self.baseView];
设置拍摄类型,隐藏工具栏,也就是拍摄按钮之类。
*预览图:这个就是拍摄之后的图片展示的。这个不是我们这次说的重点,看下Demo
就行了,这里不多提了。
遮罩区:创建一个遮罩
View
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor clearColor];
//遮罩View
self.mView = [[UIView alloc] initWithFrame:self.bounds];
self.mView.backgroundColor = [UIColor blackColor];
self.mView.alpha = 0.5;
[self addSubview:self.mView];
然后绘制一个矩形透明区Layer
加进去
- (void)drawRect:(CGRect)rect {
//绘制一个遮罩
//贝塞尔曲线 画一个带有圆角的矩形
UIBezierPath *bpath = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height) cornerRadius:0];
//贝塞尔曲线 画一个矩形
[bpath appendPath:[[UIBezierPath bezierPathWithRoundedRect:CGRectMake(kMarginX, kMarginY, self.frame.size.width-kMarginX*2, self.frame.size.height - kMarginY * 2) cornerRadius:0] bezierPathByReversingPath]];
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = bpath.CGPath;
//添加图层蒙板
self.mView.layer.mask = shapeLayer;
然后你可以在self.view
里面添加你的拍摄按钮。完成一个点击事件,例如我的:
- (void)start:(UIButton *)sender {
[self takePicture];
[self performSelector:@selector(hiddenBtn) withObject:self afterDelay:0.8];
if ([self.selectDelegate respondsToSelector:@selector(didSelectedButtonWithItem:)]) {
[self.selectDelegate didSelectedButtonWithItem:0];
}
}
上面代码我在调用代理之前调用了一个hiddenBtn
方法,我的目的是拍摄后延迟一会隐藏拍摄按钮再展示预览图片。这个想法其实是为了省事,正确做法是把隐藏放在获取到图片后,即在拍摄后的代理方法中。然而万万没想到这个懒惰思想造成了一个Bug
。
拍摄图片后,偶尔图片会是全黑的。黑屏了
查了一些资料得知:当拍摄的图片正在绘制的时候,如果做了有关UIKit的图层操作,会造成黑屏。
很明显,我在这里隐藏按钮是不行的,如果同时在绘制,就会黑屏。这个问题在iOS 10
出现,其他未见。
takePicture
拍摄完成后会自动调用
- (void)imagePickerController:(SNFCSCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info;
//注意SNFCSCImagePickerController被我修改过
把点击方法中的延迟隐藏代码删除,然后在这个方法中去隐藏即可。
[picker hiddenBtn];//拍照按钮隐藏 必须是拍照后隐藏,如果在拍照的同时隐藏那么会出现隐藏动画影响picker绘制问题,图片成像可能是黑色的。
我们回到界面的绘制上来。
在自定义相机页View
中的drawRect
方法中使用贝赛尔曲线绘制页面线条,例如四个角框:
UIColor *color = kLineColor;
[color set]; //设置线条颜色
UIBezierPath *path = [UIBezierPath bezierPath];
//左上角
[path moveToPoint:CGPointMake(kMarginX + kLineWidth/2, kMarginY + kLineLong + kLineWidth/2)];
[path addLineToPoint:CGPointMake(kMarginX + kLineWidth/2, kMarginY + kLineWidth/2)];
[path addLineToPoint:CGPointMake(kMarginY + kLineLong + kLineWidth/2, kMarginY + kLineWidth/2)];
path.lineWidth = kLineWidth;
//左下角
[path moveToPoint:CGPointMake(kMarginX + kLineWidth/2, CGRectGetHeight(self.frame) - kMarginY - kLineLong)];
[path addLineToPoint:CGPointMake(kMarginX + kLineWidth/2, CGRectGetHeight(self.frame) - kMarginY - kLineWidth/2)];
[path addLineToPoint:CGPointMake(kMarginX + kLineLong + kLineWidth/2, CGRectGetHeight(self.frame) - kMarginY - kLineWidth/2)];
path.lineWidth = kLineWidth;
//右上角
[path moveToPoint:CGPointMake(CGRectGetWidth(self.frame) - kMarginX - kLineLong - kLineWidth/2, kMarginY + kLineWidth/2)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(self.frame) - kMarginX - kLineWidth/2, kMarginY + kLineWidth/2)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(self.frame) - kMarginX - kLineWidth/2, kMarginY + kLineLong + kLineWidth/2)];
path.lineWidth = kLineWidth;
//右下角
[path moveToPoint:CGPointMake(CGRectGetWidth(self.frame) - kMarginX - kLineLong - kLineWidth/2, CGRectGetHeight(self.frame) - kMarginY - kLineWidth/2)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(self.frame) - kMarginX - kLineWidth/2, CGRectGetHeight(self.frame) - kMarginY - kLineWidth/2)];
[path addLineToPoint:CGPointMake(CGRectGetWidth(self.frame) - kMarginX - kLineWidth/2, CGRectGetHeight(self.frame) - kMarginY - kLineLong)];
path.lineWidth = kLineWidth;
[path stroke];
这种绘制常见于二维码相机自定义中,其他绘制就不举例了。