200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > Android 裁剪摄像头预览窗口-SurfaceView

Android 裁剪摄像头预览窗口-SurfaceView

时间:2024-01-29 01:54:40

相关推荐

Android 裁剪摄像头预览窗口-SurfaceView

概述

Android 下, 使用SurfaceView显示摄像头预览, 通常使用的是一个矩形窗口, 如果, 要使用一个圆形窗口呢?

先上效果图

未打开摄像头

打开摄像头

实现过程

视图布局

实现圆形裁剪的方法有很多, 最简单的, 可以在SurfaceView上方增加一个视图遮罩, 挡住不需要显示的区域即可

遮罩的方法有一个问题:

上图中, 属于ImageView的红色区域也会被遮挡

本文中采用的方法是:

用一个RelativeLayout包含SurfaceView, 通过裁剪RelativeLayout来实现:

@Overrideprotected void dispatchDraw(Canvas canvas) {//裁剪圆型画布,使SurfaceView显示圆形区域图像canvas.save();canvas.clipPath(path);super.dispatchDraw(canvas);canvas.restore();}

增加按键位置的拖动功能, 主要是为了解决验证一个问题:

//设置输入监听, 用于拖动按键位置.btn.setOnTouchListener(new View.OnTouchListener() {float cx, cy, dx, dy;int tx, ty;@Overridepublic boolean onTouch(View v, MotionEvent event) {cx = event.getRawX();cy = event.getRawY();switch(event.getAction()){case MotionEvent.ACTION_DOWN:dx = cx;dy = cy;tx = lpBtn.leftMargin;ty = lpBtn.topMargin;break;case MotionEvent.ACTION_MOVE:lpBtn.leftMargin = (int)(tx + (cx - dx));lpBtn.topMargin = (int)(ty + (cy - dy));btn.setLayoutParams(lpBtn);break;case MotionEvent.ACTION_UP://开始预览cameraHelper.openCamera(false);cameraHelper.startPreview(null);//必须设置为FALSE//sv.setZOrderOnTop(false);rlRoot.requestLayout();break;}return false;}});

当写完代码开始在设备上运行调试时, 出现了一个奇怪的问题:

当系统显示导航栏时, 可以正常显示裁剪后的圆形, 在全屏或隐藏导航栏后, 裁剪失效了:

要解决这个问题也简单, 只需要在**XRelativeLayout(rl)**中的SurfaceView上, 覆盖一个控件, 源码中已注释

//MUST add view overlayrl.addView(new View(this));

当然也可以增加到rlRoot中, 从上面的动图可以看到, 裁剪的有效范围与Button的位置有关.

参考代码

import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Path;import android.graphics.PixelFormat;import android.os.Bundle;import android.os.SystemClock;import android.view.MotionEvent;import android.view.SurfaceView;import android.view.View;import android.widget.Button;import android.widget.ImageView;import android.widget.RelativeLayout;import android.app.Activity;public class CameraPreview extends Activity {int cameraId = 1;//根控件RelativeLayout rlRoot;CameraHelper cameraHelper;SurfaceView sv;RelativeLayoutX rl;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);rlRoot = new RelativeLayout(this);//显示于SurfaceView 下方的ImageViewImageView iv = new ImageView(this);RelativeLayout.LayoutParams lpIv = new RelativeLayout.LayoutParams(UiTools.WRAP_CONTENT, UiTools.WRAP_CONTENT);iv.setScaleType(ImageView.ScaleType.FIT_XY);iv.setImageResource(R.drawable.ic_drawer_product_imgs);iv.setOnTouchListener(new View.OnTouchListener() {float cx, cy, dx, dy;int tx, ty;@Overridepublic boolean onTouch(View v, MotionEvent event) {cx = event.getRawX();cy = event.getRawY();switch(event.getAction()){case MotionEvent.ACTION_DOWN:dx = cx;dy = cy;tx = lpIv.leftMargin;ty = lpIv.topMargin;break;case MotionEvent.ACTION_MOVE://同样有效//btn.setTranslationX(tx + (cx - dx));//btn.setTranslationY(ty + (cy - dy));lpIv.leftMargin = (int)(tx + (cx - dx));lpIv.topMargin = (int)(ty + (cy - dy));iv.setLayoutParams(lpIv);break;}return true;}});rlRoot.addView(iv, lpIv);//SurfaceViewrl = new RelativeLayoutX(this);sv = new SurfaceView(this);//当未打开摄像头开始预览时, 显示透明(不设置则显示黑色)//sv.setZOrderOnTop(true);//sv.getHolder().setFormat(PixelFormat.TRANSLUCENT);rl.addView(sv, new RelativeLayout.LayoutParams(UiTools.MATCH_PARENT, UiTools.MATCH_PARENT));cameraHelper = new CameraHelper(camBase.getParameters(cameraId), sv, camBase);rlRoot.addView(rl);//MUST add view overlay//rl.addView(new View(this));RelativeLayout.LayoutParams lpBtn = new RelativeLayout.LayoutParams(UiTools.WRAP_CONTENT, UiTools.WRAP_CONTENT);Button btn = new Button(this);btn.setText("Show");//设置输入监听, 用于拖动按键位置.btn.setOnTouchListener(new View.OnTouchListener() {float cx, cy, dx, dy;int tx, ty;@Overridepublic boolean onTouch(View v, MotionEvent event) {cx = event.getRawX();cy = event.getRawY();switch(event.getAction()){case MotionEvent.ACTION_DOWN:dx = cx;dy = cy;tx = lpBtn.leftMargin;ty = lpBtn.topMargin;break;case MotionEvent.ACTION_MOVE:lpBtn.leftMargin = (int)(tx + (cx - dx));lpBtn.topMargin = (int)(ty + (cy - dy));btn.setLayoutParams(lpBtn);break;case MotionEvent.ACTION_UP://开始预览cameraHelper.openCamera(false);cameraHelper.startPreview(null);//必须设置为FALSE//sv.setZOrderOnTop(false);rlRoot.requestLayout();break;}return false;}});rlRoot.addView(btn, lpBtn);setContentView(rlRoot);}@Overrideprotected void onDestroy() {super.onDestroy();cameraHelper.stopPreview();}static class RelativeLayoutX extends RelativeLayout{public RelativeLayoutX(Context context) {super(context);}Path path = new Path();@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);path.reset();path.addCircle(w/2f, h/2f, Math.min(w, h)/2f, Path.Direction.CW);}@Overrideprotected void dispatchDraw(Canvas canvas) {//裁剪圆型画布,使SurfaceView显示圆形区域图像canvas.save();canvas.clipPath(path);super.dispatchDraw(canvas);canvas.restore();}}//非关键代码, 主要用于返回打开摄像头预览的参数CameraHelper.CameraBase camBase = new CameraHelper.CameraBaseSimple(){@Overridepublic CameraHelper.CameraParams getParameters(int camIndex) {return new CameraHelper.CameraParams(cameraId, 640, 480, 30, 0, 0);}@Overridepublic boolean sameParams(CameraHelper.CameraParams cp) {return true;}@Overridepublic void onPreviewStarted(int camIndex) {}@Overridepublic void onCameraError(int error) {}};}

PS

虽然提出了需求, 也实现了想要的效果, 却也留下了一个问题, 问题虽然解决, 但却找不到具体的原因!

浮动窗的情况未测试过Dialog或其它弹出窗口未测试过setZOrderOnTop(true)的情况未有好的解决办法

参考

解决SurfaceView渲染的各种疑难杂症

android 圆形相机预览拍照_Android相机(摄像头)圆形预览窗口,圆形SurfaceView

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。