热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Android仿支付宝人脸识别UI

前言前一段时间做人脸识别,UI设计师也是惯用“cv”大法,做了一个仿支付宝的UI,这里就总结一下自定义仿支付宝人脸识别界面UI,人脸识

前言

前一段时间做人脸识别,UI设计师也是惯用“cv”大法,做了一个仿支付宝的UI,这里就总结一下自定义仿支付宝人脸识别界面UI,人脸识别产品为公司产品不便于贴出来,这里就用前置摄像头画面代替。

需求

首先我们看看支付宝人脸识别UI界面

Android 仿支付宝人脸识别UI
image
Android 仿支付宝人脸识别UI
image

需求分析:
根据人脸的情况中间提示语不断变化,外边的进度条也会根据人脸情况动态变化,根据支付宝界面实现效果。

Android 仿支付宝人脸识别UI
image

实现

这里用两种方式实现一种继承SurfaceView自定义,另一种是继承View自定义,第一种方式将预览视频流一起绘制,也可以作为一个蒙版覆盖上面。

1、attrs.xml配置自定义属性

这里只将提示框文字的大小、颜色、内容暴露出来,其他控件颜色可自行修改

2、控件代码实现
SurfaceView实现

public class FaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { private final String TAG = "FaceView"; private SurfaceHolder mSurfaceHolder; /** * 是否可以开始绘制了 */ private boolean mStart = false; /** * 默认中间圆的半径从0开始 */ private float currentRadius = 0; /** * 控件的宽度(默认) */ private int mViewWidth = 400; /** * 控件高度 */ private int mViewHeight = 400; /** * 中心圆屏幕边距 */ private int margin; /** * 圆圈画笔 */ private Paint mPaint; /** * 提示文本 */ private String mTipText; /** * 提示文本颜色 */ private int mTipTextColor; /** * 提示文本颜色 */ private int mTipTextSize; /** * 内圆半径 */ private int mRadius; /** * 背景弧宽度 */ private float mBgArcWidth; /** * 圆心点坐标 */ private Point mCenterPoint = new Point(); /** * 圆弧边界 */ private RectF mBgRectF = new RectF(); /** * 开始角度 */ private int mStartAngle = 105; /** * 结束角度 */ private int mEndAngle = 330; /** * 圆弧背景画笔 */ private Paint mBgArcPaint; /** * 提示语画笔 */ private Paint mTextPaint; /** * 圆弧画笔 */ private Paint mArcPaint; /** * 渐变器 */ private SweepGradient mSweepGradient; /** * 是否开始 */ private boolean isRunning = true; /** * 是否后退 */ private boolean isBack = false; /** * 绘制速度 */ private int speed = 5; /** * 设置默认转动角度0 */ float currentAngle = 0; public FaceView(Context context) { this(context, null); } public FaceView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //获取xml里面的属性值 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FaceView); mTipText = array.getString(R.styleable.FaceView_tip_text); mTipTextColor = array.getColor(R.styleable.FaceView_tip_text_color, Color.WHITE); mTipTextSize = array.getDimensionPixelSize(R.styleable.FaceView_tip_text_size, ScreenUtils.sp2px(context, 12)); array.recycle(); Log.d(TAG, "FaceView构造"); initHolder(context); } /** * 初始化控件View */ private void initHolder(Context context) { //获得SurfaceHolder对象 mSurfaceHolder = getHolder(); //设置透明背景 mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT); //添加回调 mSurfaceHolder.addCallback(this); //显示顶层 setZOrderOnTop(true); //防止遮住控件 setZOrderMediaOverlay(true); //屏蔽界面焦点 setFocusable(true); //保持屏幕长亮 setKeepScreenOn(true); //初始化值 margin = ScreenUtils.dp2px(context, 60); mBgArcWidth = ScreenUtils.dp2px(context, 5); //初始化画笔 mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(getResources().getColor(R.color.colorAccent)); mPaint.setStyle(Paint.Style.FILL); //绘制文字画笔 mTextPaint = new Paint(); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setStrokeWidth(8); mTextPaint.setColor(mTipTextColor); mTextPaint.setTextSize(mTipTextSize); mTextPaint.setTextAlign(Paint.Align.CENTER); // 圆弧背景 mBgArcPaint = new Paint(); mBgArcPaint.setAntiAlias(true); mBgArcPaint.setColor(getResources().getColor(R.color.circleBg)); mBgArcPaint.setStyle(Paint.Style.STROKE); mBgArcPaint.setStrokeWidth(mBgArcWidth); mBgArcPaint.setStrokeCap(Paint.Cap.ROUND); // 圆弧 mArcPaint = new Paint(); mArcPaint.setAntiAlias(true); mArcPaint.setStyle(Paint.Style.STROKE); mArcPaint.setStrokeWidth(mBgArcWidth); mArcPaint.setStrokeCap(Paint.Cap.ROUND); //开启线程检测 new Thread(this).start(); } @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { mStart = true; Log.d(TAG, "surfaceCreated()"); } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) { Log.d(TAG, "surfaceChanged()"); } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { mStart = false; Log.d(TAG, "surfaceDestroyed()"); } @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量view的宽度 int widthMode = MeasureSpec.getMode(widthMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { mViewWidth = MeasureSpec.getSize(widthMeasureSpec); } //测量view的高度 int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode == MeasureSpec.EXACTLY) { mViewHeight = MeasureSpec.getSize(heightMeasureSpec); } setMeasuredDimension(mViewWidth, mViewHeight); Log.d(TAG, "onMeasure mViewWidth : " + mViewWidth + " mViewHeight : " + mViewHeight); //获取圆的相关参数 mCenterPoint.x = mViewWidth / 2; mCenterPoint.y = mViewHeight / 2; //外环圆的半径 mRadius = mCenterPoint.x - margin; //绘制背景圆弧的边界 mBgRectF.left = mCenterPoint.x - mRadius - mBgArcWidth / 2; mBgRectF.top = mCenterPoint.y - mRadius - mBgArcWidth / 2; mBgRectF.right = mCenterPoint.x + mRadius + mBgArcWidth / 2; mBgRectF.bottom = mCenterPoint.y + mRadius + mBgArcWidth / 2; //进度条颜色 -mStartAngle将位置便宜到原处 mSweepGradient = new SweepGradient(mCenterPoint.x - mStartAngle, mCenterPoint.y - mStartAngle, getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorPrimaryDark)); } @Override public void run() { //循环绘制画面内容 while (true) { if (mStart) { drawView(); } } } private void drawView() { Canvas canvas = null; try { //获得canvas对象 canvas = mSurfaceHolder.lockCanvas(); //清除画布上面里面的内容 canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); //绘制画布内容 drawContent(canvas); } catch (Exception e) { e.printStackTrace(); } finally { if (canvas != null) { //释放canvas锁,并且显示视图 mSurfaceHolder.unlockCanvasAndPost(canvas); } } } /** * 跟新提示信息 * * @param title */ public void updateTipsInfo(String title) { mTipText = title; } private void drawContent(Canvas canvas) { //防止save()和restore()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响 canvas.save(); //先画提示语 drawHintText(canvas); //绘制正方形的框内类似人脸识别 // drawFaceRectTest(canvas); //绘制人脸识别部分 drawFaceCircle(canvas); //画外边进度条 drawRoundProgress(canvas); canvas.restore(); } private void drawFaceCircle(Canvas canvas) { // 圆形,放大效果 currentRadius += 20; if (currentRadius > mRadius) currentRadius = mRadius; //设置画板样式 Path path = new Path(); //以(400,200)为圆心,半径为100绘制圆 指创建顺时针方向的矩形路径 path.addCircle(mCenterPoint.x, mCenterPoint.y, currentRadius, Path.Direction.CW); // 是A形状中不同于B的部分显示出来 canvas.clipPath(path, Region.Op.DIFFERENCE); // 半透明背景效果 canvas.clipRect(0, 0, mViewWidth, mViewHeight); //绘制背景颜色 canvas.drawColor(getResources().getColor(R.color.viewBgWhite)); } /** * 绘制人脸识别界面进度条 * * @param canvas canvas */ private void drawRoundProgress(Canvas canvas) { // 逆时针旋转105度 canvas.rotate(mStartAngle, mCenterPoint.x, mCenterPoint.y); // 设置圆环背景 canvas.drawArc(mBgRectF, 0, mEndAngle, false, mBgArcPaint); //判断是否正在运行 if (isRunning) { if (isBack) { currentAngle -= speed; if (currentAngle = mEndAngle) currentAngle = mEndAngle; } } // 设置渐变颜色 mArcPaint.setShader(mSweepGradient); canvas.drawArc(mBgRectF, 0, currentAngle, false, mArcPaint); } /** * 从头位置开始动画 */ public void resetPositionStart() { currentAngle = 0; isBack = false; } /** * 动画直接完成 */ public void finnishAnimator() { currentAngle = mEndAngle; isBack = false; } /** * 停止动画 */ public void pauseAnimator() { isRunning = false; } /** * 开始动画 */ public void startAnimator() { isRunning = true; } /** * 动画回退 */ public void backAnimator() { isRunning = true; isBack = true; } /** * 动画前进 */ public void forwardAnimator() { isRunning = true; isBack = false; } /** * 绘制人脸识别提示 * * @param canvas canvas */ private void drawHintText(Canvas canvas) { //圆视图宽度 (屏幕减去两边距离) int cameraWidth = mViewWidth - 2 * margin; //x轴起点(文字背景起点) int x = margin; //宽度(提示框背景宽度) int width = cameraWidth; //y轴起点 int y = (int) (mCenterPoint.y - mRadius); //提示框背景高度 int height = cameraWidth / 4; Rect rect = new Rect(x, y, x + width, y + height); canvas.drawRect(rect, mPaint); //计算baseline Paint.FontMetrics fOntMetrics= mTextPaint.getFontMetrics(); float distance = (fontMetrics.bottom - fontMetrics.top) / 4; float baseline = rect.centerY() + distance; canvas.drawText(mTipText, rect.centerX(), baseline, mTextPaint); } /** * 绘制人脸识别矩形区域 * * @param canvas canvas */ private void drawFaceRectTest(Canvas canvas) { int cameraWidth = mViewWidth - 2 * margin; int x = margin + cameraWidth / 6; int width = cameraWidth * 2 / 3; int y = mCenterPoint.x + (width / 2); int height = width; Rect rect = new Rect(x, y, x + width, y + height); mPaint.setColor(Color.GREEN); mPaint.setStyle(Paint.Style.STROKE); canvas.drawRect(rect, mPaint); } }

当获取canvas 实例后,可以将视频流一样画置SurfaceView上面

View实现

步骤:
1、自定义View的属性
2、在自定义View的构造方法中获取View属性值
3、重写onMeasure(int,int)方法
4、重写onDraw(Canvas canvas)方法

public class FaceView2 extends View implements Runnable { private final String TAG = "FaceView"; /** * 是否可以开始绘制了 */ private boolean mStart = false; /** * 默认中间圆的半径从0开始 */ private float currentRadius = 0; /** * 控件的宽度(默认) */ private int mViewWidth = 400; /** * 控件高度 */ private int mViewHeight = 400; /** * 中心圆屏幕边距 */ private int margin; /** * 圆圈画笔 */ private Paint mPaint; /** * 提示文本 */ private String mTipText; /** * 提示文本颜色 */ private int mTipTextColor; /** * 提示文本颜色 */ private int mTipTextSize; /** * 内圆半径 */ private int mRadius; /** * 背景弧宽度 */ private float mBgArcWidth; /** * 圆心点坐标 */ private Point mCenterPoint = new Point(); /** * 圆弧边界 */ private RectF mBgRectF = new RectF(); /** * 开始角度 */ private int mStartAngle = 105; /** * 结束角度 */ private int mEndAngle = 330; /** * 设置默认转动角度0 */ float currentAngle = 0; /** * 圆弧背景画笔 */ private Paint mBgArcPaint; /** * 提示语画笔 */ private Paint mTextPaint; /** * 圆弧画笔 */ private Paint mArcPaint; /** * 渐变器 */ private SweepGradient mSweepGradient; /** * 是否开始 */ private boolean isRunning = true; /** * 是否后退 */ private boolean isBack = false; /** * 绘制速度 */ private int speed = 5; public FaceView2(Context context) { this(context, null); } public FaceView2(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FaceView2(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); //获取xml里面的属性值 TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FaceView); mTipText = array.getString(R.styleable.FaceView_tip_text); mTipTextColor = array.getColor(R.styleable.FaceView_tip_text_color, Color.WHITE); mTipTextSize = array.getDimensionPixelSize(R.styleable.FaceView_tip_text_size, ScreenUtils.sp2px(context, 12)); array.recycle(); Log.d(TAG, "FaceView构造"); initPaint(context); } /** * 初始化控件View */ private void initPaint(Context context) { //获取界面焦点 setFocusable(true); //保持屏幕长亮 setKeepScreenOn(true); //初始化值 margin = ScreenUtils.dp2px(context, 60); mBgArcWidth = ScreenUtils.dp2px(context, 5); //初始化画笔 mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(getResources().getColor(R.color.colorAccent)); mPaint.setStyle(Paint.Style.FILL); //绘制文字画笔 mTextPaint = new Paint(); mTextPaint.setStyle(Paint.Style.FILL); mTextPaint.setStrokeWidth(8); mTextPaint.setColor(mTipTextColor); mTextPaint.setTextSize(mTipTextSize); mTextPaint.setTextAlign(Paint.Align.CENTER); // 圆弧背景 mBgArcPaint = new Paint(); mBgArcPaint.setAntiAlias(true); mBgArcPaint.setColor(getResources().getColor(R.color.circleBg)); mBgArcPaint.setStyle(Paint.Style.STROKE); mBgArcPaint.setStrokeWidth(mBgArcWidth); mBgArcPaint.setStrokeCap(Paint.Cap.ROUND); // 圆弧 mArcPaint = new Paint(); mArcPaint.setAntiAlias(true); mArcPaint.setStyle(Paint.Style.STROKE); mArcPaint.setStrokeWidth(mBgArcWidth); mArcPaint.setStrokeCap(Paint.Cap.ROUND); //开启线程检测 new Thread(this).start(); } @SuppressLint("DrawAllocation") @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { //测量view的宽度 int widthMode = MeasureSpec.getMode(widthMeasureSpec); if (widthMode == MeasureSpec.EXACTLY) { mViewWidth = MeasureSpec.getSize(widthMeasureSpec); } //测量view的高度 int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode == MeasureSpec.EXACTLY) { mViewHeight = MeasureSpec.getSize(heightMeasureSpec); } setMeasuredDimension(mViewWidth, mViewHeight); Log.d(TAG, "onMeasure mViewWidth : " + mViewWidth + " mViewHeight : " + mViewHeight); //获取圆的相关参数 mCenterPoint.x = mViewWidth / 2; mCenterPoint.y = mViewHeight / 2; //外环圆的半径 mRadius = mCenterPoint.x - margin; //绘制背景圆弧的边界 mBgRectF.left = mCenterPoint.x - mRadius - mBgArcWidth / 2; mBgRectF.top = mCenterPoint.y - mRadius - mBgArcWidth / 2; mBgRectF.right = mCenterPoint.x + mRadius + mBgArcWidth / 2; mBgRectF.bottom = mCenterPoint.y + mRadius + mBgArcWidth / 2; //进度条颜色 -mStartAngle/2将位置到原处 mSweepGradient = new SweepGradient(mCenterPoint.x - mStartAngle / 2, mCenterPoint.y - mStartAngle / 2, getResources().getColor(R.color.colorPrimary), getResources().getColor(R.color.colorPrimaryDark)); } @Override protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); mStart = (visibility == VISIBLE); } @Override public void run() { //循环绘制画面内容 while (true) { if (mStart) { try { changeValue(); Thread.sleep(50); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * 动态检测改变值 */ private void changeValue() { // 内圆形,放大效果 currentRadius += 20; if (currentRadius > mRadius) currentRadius = mRadius; //外部圈的动画效果 if (isRunning) { if (isBack) { currentAngle -= speed; if (currentAngle = mEndAngle) currentAngle = mEndAngle; } } //重绘view invalidate(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); //绘制画布内容 drawContent(canvas); } /** * 跟新提示信息 * * @param title */ public void updateTipsInfo(String title) { mTipText = title; } private void drawContent(Canvas canvas) { //防止save()和restore()方法代码之后对Canvas执行的操作,继续对后续的绘制会产生影响 canvas.save(); //先画提示语 drawHintText(canvas); //绘制正方形的框内类似人脸识别 // drawFaceRectTest(canvas); //绘制人脸识别部分 drawFaceCircle(canvas); //画外边进度条 drawRoundProgress(canvas); canvas.restore(); } private void drawFaceCircle(Canvas canvas) { //设置画板样式 Path path = new Path(); //以(400,200)为圆心,半径为100绘制圆 指创建顺时针方向的矩形路径 path.addCircle(mCenterPoint.x, mCenterPoint.y, currentRadius, Path.Direction.CW); // 是A形状中不同于B的部分显示出来 canvas.clipPath(path, Region.Op.DIFFERENCE); // 半透明背景效果 canvas.clipRect(0, 0, mViewWidth, mViewHeight); //绘制背景颜色 canvas.drawColor(getResources().getColor(R.color.viewBgWhite)); } /** * 绘制人脸识别界面进度条 * * @param canvas canvas */ private void drawRoundProgress(Canvas canvas) { // 逆时针旋转105度 canvas.rotate(mStartAngle, mCenterPoint.x, mCenterPoint.y); // 设置圆环背景 canvas.drawArc(mBgRectF, 0, mEndAngle, false, mBgArcPaint); // 设置渐变颜色 mArcPaint.setShader(mSweepGradient); canvas.drawArc(mBgRectF, 0, currentAngle, false, mArcPaint); } /** * 从头位置开始动画 */ public void resetPositionStart() { currentAngle = 0; isBack = false; } /** * 动画直接完成 */ public void finnishAnimator() { currentAngle = mEndAngle; isBack = false; } /** * 停止动画 */ public void pauseAnimator() { isRunning = false; } /** * 开始动画 */ public void startAnimator() { isRunning = true; } /** * 动画回退 */ public void backAnimator() { isRunning = true; isBack = true; } /** * 动画前进 */ public void forwardAnimator() { isRunning = true; isBack = false; } /** * 绘制人脸识别提示 * * @param canvas canvas */ private void drawHintText(Canvas canvas) { //圆视图宽度 (屏幕减去两边距离) int cameraWidth = mViewWidth - 2 * margin; //x轴起点(文字背景起点) int x = margin; //宽度(提示框背景宽度) int width = cameraWidth; //y轴起点 int y = (int) (mCenterPoint.y - mRadius); //提示框背景高度 int height = cameraWidth / 4; Rect rect = new Rect(x, y, x + width, y + height); canvas.drawRect(rect, mPaint); //计算baseline Paint.FontMetrics fOntMetrics= mTextPaint.getFontMetrics(); float distance = (fontMetrics.bottom - fontMetrics.top) / 4; float baseline = rect.centerY() + distance; canvas.drawText(mTipText, rect.centerX(), baseline, mTextPaint); } /** * 绘制人脸识别矩形区域 * * @param canvas canvas */ private void drawFaceRectTest(Canvas canvas) { int cameraWidth = mViewWidth - 2 * margin; int x = margin + cameraWidth / 6; int width = cameraWidth * 2 / 3; int y = mCenterPoint.x + (width / 2); int height = width; Rect rect = new Rect(x, y, x + width, y + height); mPaint.setColor(Color.GREEN); mPaint.setStyle(Paint.Style.STROKE); canvas.drawRect(rect, mPaint); } }

这里值得注意的是这几个方法,使用的时候可以根据实际调用这几个动画。

/** * 从头位置开始动画 */ public void resetPositionStart() { currentAngle = 0; isBack = false; } /** * 动画直接完成 */ public void finnishAnimator() { currentAngle = mEndAngle; isBack = false; } /** * 停止动画 */ public void pauseAnimator() { isRunning = false; } /** * 开始动画 */ public void startAnimator() { isRunning = true; } /** * 动画回退 */ public void backAnimator() { isRunning = true; isBack = true; } /** * 动画前进 */ public void forwardAnimator() { isRunning = true; isBack = false; }

3、使用布局UI

4、Activity使用

public class PreviewActivity extends AppCompatActivity { private final String TAG = "PreviewActivity"; private Camera camera; private boolean isPreview = false; static final String[] PERMISSION = new String[]{ //获取照相机权限 Manifest.permission.CAMERA, }; /** * 设置Android6.0的权限申请 */ private void setPermissions() { if (ContextCompat.checkSelfPermission(PreviewActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { //Android 6.0申请权限 ActivityCompat.requestPermissions(this, PERMISSION, 1); } else { Log.i(TAG, "权限申请ok"); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_preview); //初始化布局 ConstraintLayout cOnstraintLayout= findViewById(R.id.cl_root); final FaceView faceView = findViewById(R.id.fv_title); ImageView imageView = findViewById(R.id.iv_close); //申请手机的权限 setPermissions(); imageView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int i = (int) (1 + Math.random() * 4); switch (i) { case 1: faceView.resetPositionStart(); faceView.updateTipsInfo("没有检测人脸"); break; case 2: faceView.backAnimator(); faceView.updateTipsInfo("请露正脸"); break; case 3: faceView.pauseAnimator(); faceView.updateTipsInfo(" 眨眨眼"); break; case 4: faceView.startAnimator(); faceView.updateTipsInfo("离近一点"); break; default: break; } } }); //添加布局 SurfaceView mSurfaceView = new SurfaceView(this); RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE); mSurfaceView.setLayoutParams(params); constraintLayout.addView(mSurfaceView, 0); //得到getHolder实例 SurfaceHolder mSurfaceHolder = mSurfaceView.getHolder(); mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT); // 添加 Surface 的 callback 接口 mSurfaceHolder.addCallback(mSurfaceCallback); } private SurfaceHolder.Callback mSurfaceCallback = new SurfaceHolder.Callback() { @Override public void surfaceCreated(SurfaceHolder surfaceHolder) { try { //打开硬件摄像头,这里导包得时候一定要注意是android.hardware.Camera // Camera,open() 默认返回的后置摄像头信息 //设置角度,此处 CameraId 我默认 为 1 (前置) if (Camera.getNumberOfCameras() > 1) { camera = Camera.open(1); } else { camera = Camera.open(0); } //设置相机角度 camera.setDisplayOrientation(90); //通过SurfaceView显示取景画面 camera.setPreviewDisplay(surfaceHolder); //开始预览 camera.startPreview(); //设置是否预览参数为真 isPreview = true; } catch (IOException e) { e.printStackTrace(); } } @Override public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder surfaceHolder) { if (camera != null) { if (isPreview) {//正在预览 try { camera.stopPreview(); camera.release(); } catch (Exception e) { e.printStackTrace(); } } } } }; @Override protected void onDestroy() { if (camera != null) { if (isPreview) {//正在预览 try { camera.stopPreview(); camera.release(); } catch (Exception e) { e.printStackTrace(); } } } super.onDestroy(); } }

视频流用的前置摄像头,这里的提示和动画也是随机,项目中可以根据真实情况展示。

Android 仿支付宝人脸识别UI
image

【注意】自定义view应该注意前后绘制顺序和叠加模式

总结

项目中用到就简单抽了一下,有遇到类似需求可以参考一下,最近在学Flutter,学的差不多了写个Flutter版本在更新一下。。。

声明:

转载请注明出处

作者:戎码虫
链接:https://www.jianshu.com/p/625266dfab1d


推荐阅读
author-avatar
莫不静了_660
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有