Uniapp自定义相机界面

Uniapp是一款入门门槛比较低的跨平台开发方案,一套代码可以生成Android、IOS、H5、微信\QQ\支付宝\头条\飞书等若高个平台的小程序,因此很多中小型公司都会考虑用这种方案来实现业务需求;最近公司就要在原有功能上增加水印相机功能,原本如果是原生的Android或IOS很容易实现,不过因为项目是用uniapp搭建的,发现uniapp只能简单调用系统的相机来拍照或录像,哎,可是我们的设计图可是要自定义界面的,这里就卡死了,于是开始寻找解决方案,于是在官网找插件,(看到其他原生相机相关插件的价格,心里拔凉拔凉的,基本都是几百到上千起步,关键这玩意老板不给报销啊),不过也有收获,那就是知道了肯定是可以弄出来自定义界面的效果的,也算吃了半颗定心丸,uniapp这个原生插件的功能(反正就是你可以在Android或IOS端用原生代码来实现功能,然后打包给Uniapp的代码调用),喜出望外呀!于是立刻着手研究原生插件,好在之前好几年的原生Android开发经验,网上找了下资料,封装了一个自定义相机类,不过还是费了老劲了,因为不熟悉Uniapp下的原生插件开发原理,走了很多弯路,所幸还是做出来了一个仅支持Android端的原生插件。乘胜追击!又开始摸索IOS端,因为对IOS端的Object-c和swift都不熟悉,网上找了例子看起来也挺费劲,研究了三天,github上下了十几个demo,一一看完,总算有了个眉目(说句题外话,swift代码风格真的比OC要轻巧很多),一款新的跨Android/IOS两端的原生插件诞生了!最近又优化了一波内容更新到了2.0版本:上图–>

下面展示一些 内联代码片

这个是Android端实现原生插件的方法,返回一个FrameLayout组件便于后面的扩展,addView添加了一个SurfaceView用于显示摄像头的预览效果
   @Override
    protected FrameLayout initComponentHostView(Context context) {
        FrameLayout frameLayout = new FrameLayout(context);
        UniLogUtils.e("绘制帧布局;;;");
        SurfaceView surfaceView = new SurfaceView(context);
        frameLayout.addView(surfaceView);
        if (mHolder == null) {
            mHolder = surfaceView.getHolder();

            mHolder.addCallback(new SurfaceHolder.Callback() {
                @Override
                public void surfaceCreated(SurfaceHolder holder) {
//                    UniLogUtils.e("开始绘制:");
//                    Canvas canvas = holder.lockCanvas();
//                    Paint paint = new Paint();
//                    paint.setColor(Color.WHITE);
//                    paint.setTextSize(22);
//                    canvas.drawText(locationAddress,200,300,paint);
//                    holder.unlockCanvasAndPost(canvas);
//                    UniLogUtils.e("结束绘制:");
                    initCamera();
                }

                @Override
                public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

                }

                @Override
                public void surfaceDestroyed(SurfaceHolder holder) {

                }
            });
        }

        return frameLayout;
    }

IOS端的实现代码,相比Android简单很多,loadView里返回了一个UIView对象,原生插件有两种模式,module和component,简单说就是前者重点在功能,后者重点在界面。viewDidLoad里配置了AVCaptureSession的一些信息,拍照录像都需要使用AVCaptureSession来完成

- (UIView *)loadView {
    NSLog(@"插件日志:loadView");
    return [UIView new];
}

- (void)viewDidLoad {
    NSLog(@"插件日志:viewDidLoad");
    
    self.session = [[AVCaptureSession alloc] init];
    
    //创建一个AVCaptureMovieFileOutput 实例,用于将Quick Time 电影录制到文件系统
    self.movieOutput = [[AVCaptureMovieFileOutput alloc]init];
    //输出连接 判断是否可用,可用则添加到输出连接中去
    if ([self.session canAddOutput:self.movieOutput])
    {
        [self.session addOutput:self.movieOutput];
    }
    
    //     拿到的图像的大小可以自行设定
    //    AVCaptureSessionPresetHigh
    //    AVCaptureSessionPreset320x240
    //    AVCaptureSessionPreset352x288
    //    AVCaptureSessionPreset640x480
    //    AVCaptureSessionPreset960x540
    //    AVCaptureSessionPreset1280x720
    //    AVCaptureSessionPreset1920x1080
    //    AVCaptureSessionPreset3840x2160
    self.session.sessionPreset = AVCaptureSessionPreset1920x1080;
    
    //AVCaptureStillImageOutput 实例 从摄像头捕捉静态图片
    self.imageOutput = [[AVCaptureStillImageOutput alloc]init];
    //配置字典:希望捕捉到JPEG格式的图片
    self.imageOutput.outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG};
    if ([self.session canAddOutput:self.imageOutput]) {
        [self.session addOutput:self.imageOutput];
    }

    self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
    NSError * error = nil;
    self.input = [AVCaptureDeviceInput deviceInputWithDevice:self.device error:&error];
    
    if (self.input) {
        [self.session addInput:self.input];
    }else{
        NSLog(@"Input Error:%@",error);
    }

    //预览层的生成
    self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
    
    // 直接取用本组件的bounds来做定位,因为本组件的bounds是uniapp传过来的css宽高设置过的
    self.previewLayer.frame = self.view.bounds; //预览层填充视图

    // AVLayerVideoGravityResizeAspectFill 等比例填充,直到填充满整个视图区域,其中一个维度的部分区域会被裁剪
    // AVLayerVideoGravityResize 非均匀模式。两个维度完全填充至整个视图区域
    // AVLayerVideoGravityResizeAspect 等比例填充,直到一个维度到达区域边界
    self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
    [self.view.layer addSublayer:self.previewLayer];

    [self.session startRunning];
}

插件地址:link
效果展示:
录像功能
相机功能

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值