作者: Jooyer, 時間: 2019.01.08
Github地址,歡迎點贊,fork
現在部分APP都有一個身份認證,一般需要身份證正面,反面,在度娘那也有很多,我發現他們在屬性配置上略少了一些,所以特意寫了一個!,四周線條顏色,間距,粗細都有屬性設定!
本次程式碼也是比較簡單,就一個系統的 SurfaceView 和 一個自定義的View, 我就直接貼原始碼,如果還有不清楚的,可以留言或者看github
接下來我們依次講解:
- CameraSufaceView
- CameraMaskView
- 屬性及預設值
首先,看看 CameraSufaceView,必要的註釋都有
package cn.molue.jooyer.masker;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.Environment;
import android.support.constraint.ConstraintLayout;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.Toast;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.List;
/**
* @Date 2018/12/29
* @Desc 相機預覽介面
*/
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.AutoFocusCallback {
private static final String TAG = "CameraSurfaceView";
private SurfaceHolder holder;
private Camera mCamera;
private Rect mCenterMarkRect;
private int mScreenWidth;
private int mScreenHeight;
private File mFile;
private OnPathChangedListener onPathChangedListener;
public void setOnPathChangedListener(OnPathChangedListener onPathChangedListener) {
this.onPathChangedListener = onPathChangedListener;
}
public CameraSurfaceView(Context context) {
this(context, null);
}
public CameraSurfaceView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CameraSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
getScreenMetrix(context);
initView();
}
//拿到手機螢幕大小
private void getScreenMetrix(Context context) {
mScreenWidth = context.getResources().getDisplayMetrics().widthPixels;
mScreenHeight = context.getResources().getDisplayMetrics().heightPixels;
}
private void initView() {
//獲得surfaceHolder引用
holder = getHolder();
// 螢幕常亮
holder.setKeepScreenOn(true);
//為SurfaceView的控制程式碼新增一個回撥函式
holder.addCallback(this);
// holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);//設定型別
}
// 在surface建立後立即被呼叫。在開發自定義相機時,可以通過過載這個函式呼叫camera.open()、camera.setPreviewDisplay(),
// 來實現獲取相機資源、連線camera和surface等操作
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
if (mCamera == null) {
mCamera = Camera.open();
try {
// 設定用於顯示拍照影像的SurfaceHolder物件
mCamera.setPreviewDisplay(holder);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 可以通過過載這個函式呼叫camera.startPreview來開啟相機預覽,使得camera預覽幀資料可以傳遞給surface,從而實時顯示相機預覽影象
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
setCameraParams(mScreenWidth, mScreenHeight);
mCamera.startPreview();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
mCamera.stopPreview();//停止預覽
mCamera.release();//釋放相機資源
mCamera = null;
}
@Override
public void onAutoFocus(boolean success, Camera Camera) {
}
private void setCameraParams(int width, int height) {
Log.i(TAG, "------setCameraParams width=" + width + " height=" + height);
Camera.Parameters parameters = mCamera.getParameters();
// 獲取攝像頭支援的PictureSize列表
List<Camera.Size> pictureSizeList = parameters.getSupportedPictureSizes();
/**從列表中選取合適的解析度*/
Camera.Size picSize = getProperSize(pictureSizeList, ((float) height / width));
if (null == picSize) {
Log.i(TAG, "null == picSize");
picSize = parameters.getPictureSize();
}
// 根據選出的PictureSize重新設定SurfaceView大小
float w = picSize.width;
float h = picSize.height;
Log.i(TAG, "----------picSize.width=" + picSize.width + " --- picSize.height=" + picSize.height);
// 設定捕獲圖片尺寸
parameters.setPictureSize(picSize.width, picSize.height);
this.setLayoutParams(new ConstraintLayout.LayoutParams((int) (height * (h / w)), height));
// 獲取攝像頭支援的PreviewSize列表
List<Camera.Size> previewSizeList = parameters.getSupportedPreviewSizes();
Camera.Size preSize = getProperSize(previewSizeList, ((float) height) / width);
if (null != preSize) {
Log.i(TAG, "----------preSize.width=" + preSize.width + " --- preSize.height=" + preSize.height);
// 設定預覽圖片尺寸
parameters.setPreviewSize(preSize.width, preSize.height);
}
parameters.setJpegQuality(100); // 設定照片質量
if (parameters.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);// 連續對焦模式
}
mCamera.cancelAutoFocus();//自動對焦。
mCamera.setParameters(parameters);
// 計算攝像頭方向
Camera.CameraInfo info =
new Camera.CameraInfo();
Camera.getCameraInfo(0, info);
int rotation = ((Activity) getContext()).getWindowManager().getDefaultDisplay()
.getRotation();
int degrees = 0;
switch (rotation) {
case Surface.ROTATION_0:
degrees = 0;
break;
case Surface.ROTATION_90:
degrees = 90;
break;
case Surface.ROTATION_180:
degrees = 180;
break;
case Surface.ROTATION_270:
degrees = 270;
break;
}
int result;
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
result = (info.orientation + degrees) % 360;
result = (360 - result) % 360; // compensate the mirror
} else { // back-facing
result = (info.orientation - degrees + 360) % 360;
}
// 設定PreviewDisplay的方向,效果就是將捕獲的畫面旋轉多少度顯示
mCamera.setDisplayOrientation(result);
}
/**
* 從列表中選取合適的解析度
* 預設w:h = 4:3
* <p>注意:這裡的w對應螢幕的height
* h對應螢幕的width<p/>
*/
private Camera.Size getProperSize(List<Camera.Size> pictureSizeList, float screenRatio) {
Log.i(TAG, "screenRatio=" + screenRatio);
Camera.Size result = null;
for (Camera.Size size : pictureSizeList) {
float currentRatio = ((float) size.width) / size.height;
if (currentRatio - screenRatio == 0) {
result = size;
break;
}
}
if (null == result) {
for (Camera.Size size : pictureSizeList) {
float curRatio = ((float) size.width) / size.height;
if (curRatio == 4f / 3) {// 預設w:h = 4:3
result = size;
break;
}
}
}
return result;
}
// 拍照瞬間呼叫 (新增這個才會有咔嚓聲)
private Camera.ShutterCallback shutter = new Camera.ShutterCallback() {
@Override
public void onShutter() {
}
};
// 獲得沒有壓縮過的圖片資料
private Camera.PictureCallback raw = new Camera.PictureCallback() {
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
}
};
//建立jpeg圖片回撥資料物件
private Camera.PictureCallback jpeg = new Camera.PictureCallback() {
private Bitmap bitmap;
@Override
public void onPictureTaken(byte[] data, Camera Camera) {
BufferedOutputStream bos = null;
Bitmap bm = null;
if (data != null) {
}
try {
// 獲得圖片
bm = BitmapFactory.decodeByteArray(data, 0, data.length);
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
// 圖片儲存前旋轉
Matrix m = new Matrix();
int height = bm.getHeight();
int width = bm.getWidth();
m.setRotate(90);
//旋轉後的圖片
bitmap = Bitmap.createBitmap(bm, 0, 0, width, height, m, true);
String photo = "IMMQY/IMG_" + String.valueOf(new Date().getTime() + ".jpg");
mFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath(), photo);
if (!mFile.getParentFile().exists()) {
mFile.getParentFile().mkdirs();
}
bos = new BufferedOutputStream(new FileOutputStream(mFile));
if (null == mCenterMarkRect) {
throw new NullPointerException("mCenterMarkRect is not null");
}
Bitmap sizeBitmap = Bitmap.createScaledBitmap(bitmap,
mScreenWidth, mScreenHeight, true);
// 擷取
bm = Bitmap.createBitmap(sizeBitmap,
mCenterMarkRect.left, mCenterMarkRect.top,
mCenterMarkRect.right - mCenterMarkRect.left,
mCenterMarkRect.bottom - mCenterMarkRect.top);
bm.compress(Bitmap.CompressFormat.JPEG, 100, bos);//將圖片壓縮到流中
} else {
Toast.makeText(getContext(), "沒有檢測到記憶體卡", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
bos.flush();//輸出
bos.close();//關閉
bm.recycle();// 回收bitmap空間
mCamera.stopPreview();// 關閉預覽
mCamera.startPreview();// 開啟預覽
if (onPathChangedListener != null) {
onPathChangedListener.onValueChange(mFile.getPath());
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
};
/**
* 拍照
*/
public void takePicture() {
//設定引數,並拍照
setCameraParams(mScreenWidth, mScreenHeight);
// 當呼叫camera.takePiture方法後,camera關閉了預覽,這時需要呼叫startPreview()來重新開啟預覽
mCamera.takePicture(shutter, null, jpeg);
}
public void setAutoFocus() {
mCamera.autoFocus(this);
}
public void setCenterMarkRect(Rect centerMarkRect) {
this.mCenterMarkRect = centerMarkRect;
}
public interface OnPathChangedListener {
void onValueChange(String path);
}
}
複製程式碼
然後我們來瞧瞧 CameraMaskView ,其實這裡就是將四周擋住,留下中間位置作為拍照的具體內容
package cn.molue.jooyer.masker;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;
/**
* @Date 2018/12/29
* @Time 11:37
*/
public class CameraMaskView extends View {
// 預設如果方框佈局中時距離上面尺寸
private static final int MASK_MARGIN = 100;
// 預設線寬
private static final int LINE_WIDTH = 5;
// 預設線長
private static final int LINE_LENGTH = 40;
// 預設線外邊距
private static final int LINE_MARGIN = 10;
// 預設線內邊距
private static final int LINE_PADDING = 5;
// 預設提示文字
private static final String TEXT = "請將身份證置於此框內";
// 控制元件的寬高
private int viewWidth;
private int viewHeight;
// 中間透明區域(方框)寬高
public int rectWidth;
public int rectHeight;
// 提示文字
private String mTipText = "";
// 文字顏色
private int mTipTextColor = 0;
// 文字大小
private int mTipTextSize = 0;
// 文字距離底部 遮罩框 間隔
private int mTipMargin = 0;
// 中間透明區域(方框)座標
private Rect mCenterMarkRect = new Rect();
// 遮罩顏色
private int mMaskColor = 0;
// 遮罩是居中,還是居上
private int mMaskPosition = 0;
private int mMaskMargin = 0;
// 四周線條長度
private int mLineLength;
// 四周線條寬度(厚度)
private int mLineWidth;
private int mLineColor = 0;
private int mLinePadding = 0;
private int mLineMargin = 0;
// 文字畫筆
private Paint maskPaint;
// 線條畫筆
private Paint linePaint;
// 文字畫筆
private Paint wordPaint;
// 計算提示文字的位置的
private Rect rect;
// 文字基線
private int baseline;
public CameraMaskView(Context context, AttributeSet attrs) {
super(context, attrs);
parse(context, attrs);
init(context);
}
private void parse(Context context, AttributeSet attrs) {
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CameraMaskView);
mMaskMargin = (int) array.getDimension(R.styleable.CameraMaskView_cmv_mask_margin, MASK_MARGIN);
mMaskPosition = array.getInt(R.styleable.CameraMaskView_cmv_position_flag, 0);
mMaskColor = array.getColor(R.styleable.CameraMaskView_cmv_mask_color, 0xa0000000);
mTipText = array.getString(R.styleable.CameraMaskView_cmv_tip_text);
if (null == mTipText || mTipText.isEmpty()) {
mTipText = TEXT;
}
mTipTextColor = array.getColor(R.styleable.CameraMaskView_cmv_tip_color, 0xFFFFFFFF);
mTipTextSize = (int) array.getDimension(R.styleable.CameraMaskView_cmv_tip_size, sp2px(context, 14));
mTipMargin = (int) array.getDimension(R.styleable.CameraMaskView_cmv_tip_margin, dp2px(context, 20));
mLineColor = array.getColor(R.styleable.CameraMaskView_cmv_line_color, 0xFF85D28A);
mLineWidth = (int) array.getDimension(R.styleable.CameraMaskView_cmv_line_width, dp2px(context, LINE_WIDTH));
mLineLength = (int) array.getDimension(R.styleable.CameraMaskView_cmv_line_length, dp2px(context, LINE_LENGTH));
mLinePadding = (int) array.getDimension(R.styleable.CameraMaskView_cmv_line_padding, dp2px(context, LINE_PADDING));
mLineMargin = (int) array.getDimension(R.styleable.CameraMaskView_cmv_line_margin, dp2px(context, LINE_MARGIN));
array.recycle();
}
private void init(Context context) {
viewWidth = context.getResources().getDisplayMetrics().widthPixels;
viewHeight = context.getResources().getDisplayMetrics().heightPixels;
rectWidth = viewWidth - dp2px(context, 2 * mLineMargin);
// 身份證 長度85.6mm,寬度54mm
rectHeight = (int) (rectWidth * 54 / 85.6);
if (1 == mMaskPosition) {
mCenterMarkRect.left = (viewWidth - rectWidth) / 2;
mCenterMarkRect.top = mMaskMargin;
mCenterMarkRect.right = mCenterMarkRect.left + rectWidth;
mCenterMarkRect.bottom = mMaskMargin + rectHeight;
} else {
mCenterMarkRect.left = (viewWidth - rectWidth) / 2;
mCenterMarkRect.top = (viewHeight - rectHeight) / 2;
mCenterMarkRect.right = mCenterMarkRect.left + rectWidth;
mCenterMarkRect.bottom = mCenterMarkRect.top + rectHeight;
}
linePaint = new Paint();
linePaint.setAntiAlias(true);
linePaint.setColor(mLineColor);
linePaint.setStyle(Paint.Style.STROKE);
linePaint.setStrokeWidth(mLineWidth);// 設定線寬
linePaint.setAlpha(255);
maskPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
maskPaint.setColor(mMaskColor);
wordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
wordPaint.setColor(mTipTextColor);
wordPaint.setTextSize(mTipTextSize);
rect = new Rect(mCenterMarkRect.left, mCenterMarkRect.top - mTipTextSize - mTipMargin,
mCenterMarkRect.right, mCenterMarkRect.top - mTipMargin);
Paint.FontMetricsInt fontMetrics = wordPaint.getFontMetricsInt();
baseline = rect.top + (rect.bottom - rect.top - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top;
wordPaint.setTextAlign(Paint.Align.CENTER);
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (1 == mMaskPosition) {
// 頂部蒙層
canvas.drawRect(0, 0, viewWidth, mMaskMargin, maskPaint);
// 左側
canvas.drawRect(0, mMaskMargin, (viewWidth - rectWidth) / 2, mMaskMargin + rectHeight, maskPaint);
// 右側
canvas.drawRect(viewWidth - (viewWidth - rectWidth) / 2, mMaskMargin, viewWidth, mMaskMargin + rectHeight, maskPaint);
// 底部蒙層
canvas.drawRect(0, mMaskMargin + rectHeight, viewWidth, viewHeight, maskPaint);
} else {
// 頂部蒙層
canvas.drawRect(0, 0, viewWidth, viewHeight / 2 - rectHeight / 2, maskPaint);
// 左側
canvas.drawRect(0, viewHeight / 2 - rectHeight / 2, (viewWidth - rectWidth) / 2, viewHeight / 2 + rectHeight / 2, maskPaint);
// 右側
canvas.drawRect(viewWidth - (viewWidth - rectWidth) / 2, viewHeight / 2 - rectHeight / 2, viewWidth, viewHeight / 2 + rectHeight / 2, maskPaint);
// 底部蒙層
canvas.drawRect(0, viewHeight / 2 + rectHeight / 2, viewWidth, viewHeight, maskPaint);
}
// 繪製文字
canvas.drawText(mTipText, rect.centerX(), baseline, wordPaint);
// 繪製四個角
canvas.drawLine(mCenterMarkRect.left - dp2px(getContext(), mLinePadding) - mLineWidth / 2.0F, mCenterMarkRect.top - dp2px(getContext(), mLinePadding),
mCenterMarkRect.left + mLineLength, mCenterMarkRect.top - dp2px(getContext(), mLinePadding), linePaint);
canvas.drawLine(mCenterMarkRect.left - dp2px(getContext(), mLinePadding), mCenterMarkRect.top - dp2px(getContext(), mLinePadding),
mCenterMarkRect.left - dp2px(getContext(), mLinePadding), mCenterMarkRect.top + mLineLength, linePaint);
canvas.drawLine(mCenterMarkRect.right - mLineLength, mCenterMarkRect.top - dp2px(getContext(), mLinePadding),
mCenterMarkRect.right + dp2px(getContext(), mLinePadding) + mLineWidth / 2.0F, mCenterMarkRect.top - dp2px(getContext(), mLinePadding), linePaint);
canvas.drawLine(mCenterMarkRect.right + dp2px(getContext(), mLinePadding), mCenterMarkRect.top - dp2px(getContext(), mLinePadding),
mCenterMarkRect.right + dp2px(getContext(), mLinePadding), mCenterMarkRect.top + mLineLength, linePaint);
canvas.drawLine(mCenterMarkRect.left - dp2px(getContext(), mLinePadding), mCenterMarkRect.bottom - mLineLength,
mCenterMarkRect.left - dp2px(getContext(), mLinePadding), mCenterMarkRect.bottom + dp2px(getContext(), mLinePadding) + mLineWidth / 2.0F, linePaint);
canvas.drawLine(mCenterMarkRect.left - dp2px(getContext(), mLinePadding), mCenterMarkRect.bottom + dp2px(getContext(), mLinePadding),
mCenterMarkRect.left + mLineLength, mCenterMarkRect.bottom + dp2px(getContext(), mLinePadding), linePaint);
canvas.drawLine(mCenterMarkRect.right - mLineLength, mCenterMarkRect.bottom + dp2px(getContext(), mLinePadding),
mCenterMarkRect.right + dp2px(getContext(), mLinePadding) + mLineWidth / 2.0F, mCenterMarkRect.bottom + dp2px(getContext(), mLinePadding), linePaint);
canvas.drawLine(mCenterMarkRect.right + dp2px(getContext(), mLinePadding), mCenterMarkRect.bottom - mLineLength,
mCenterMarkRect.right + dp2px(getContext(), mLinePadding), mCenterMarkRect.bottom + dp2px(getContext(), mLinePadding), linePaint);
}
public Rect getCenterMarkRect() {
return mCenterMarkRect;
}
private int dp2px(Context context, float dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpValue, context.getResources().getDisplayMetrics());
}
private int sp2px(Context context, int dpValue) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, dpValue, context.getResources().getDisplayMetrics());
}
}
複製程式碼
來看看自定義的屬性(xml檔案)
裡面就是一大堆自定義的屬性,具體含義往下看
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="CameraMaskView">
<!-- 蒙層顏色 -->
<attr name="cmv_mask_color" format="color|reference" />
<!-- 提示文字 -->
<attr name="cmv_tip_text" format="string|reference" />
<!-- 文字顏色 -->
<attr name="cmv_tip_color" format="color|reference" />
<!-- 文字大小 -->
<attr name="cmv_tip_size" format="integer|dimension" />
<!-- 文字底部距離方框的間隔 -->
<attr name="cmv_tip_margin" format="integer|dimension" />
<!-- 邊線顏色 -->
<attr name="cmv_line_color" format="color|reference" />
<!-- 邊線寬度(厚度) -->
<attr name="cmv_line_width" format="integer|dimension" />
<!-- 邊線長度 -->
<attr name="cmv_line_length" format="integer|dimension" />
<!-- 邊線與內部透明方框的間隔 -->
<attr name="cmv_line_padding" format="integer|dimension" />
<!-- 邊線與外面手機螢幕邊框的間隔 -->
<attr name="cmv_line_margin" format="integer|dimension"/>
<!-- 預設方框是劇中的 -->
<attr name="cmv_position_flag">
<enum name="center" value="0"/>
<enum name="margin" value="1"/>
</attr>
<!-- 只有當設定了 cmv_position_flag = margin 才有效 -->
<attr name="cmv_mask_margin" format="integer|dimension"/>
</declare-styleable>
</resources>
複製程式碼
屬性雖然有些多,但是大都都見名知意.
最後來看看在 Activity 佈局中的用法
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".CameraActivity">
<cn.molue.jooyer.masker.CameraSurfaceView
android:id="@+id/camera_surface_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<cn.molue.jooyer.masker.CameraMaskView
android:id="@+id/camera_rect_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:cmv_line_color="#85D28A"
app:cmv_line_length="40dp"
app:cmv_line_margin="10dp"
app:cmv_line_padding="2dp"
app:cmv_line_width="2dp"
app:cmv_mask_color="#FF76635A"
app:cmv_mask_margin="80dp"
app:cmv_position_flag="margin"
app:cmv_tip_color="#FFFFFF"
app:cmv_tip_margin="40dp"
app:cmv_tip_size="15sp"
app:cmv_tip_text="請將身份證頭像面置於此框內"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<View
android:id="@+id/view_background"
android:layout_width="0dp"
android:layout_height="123dp"
android:background="#FF2F2A28"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
<TextView
android:id="@+id/text_view_cancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="33dp"
android:layout_marginEnd="50dp"
android:padding="18dp"
android:gravity="center_vertical"
android:text="取消"
android:textColor="#FFF"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toLeftOf="@id/image_view_take"
/>
<ImageView
android:id="@+id/image_view_take"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@drawable/camera_take_background"
android:layout_marginBottom="30dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
/>
</android.support.constraint.ConstraintLayout>
複製程式碼
這個就不解釋了,最後看看 Activity中的操作
package cn.molue.jooyer.masker;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
/**
* @Author Jooyer
* @Date 2018/01/08
* @Time 14.27
*/
public class CameraActivity extends AppCompatActivity {
private CameraSurfaceView cameraSurfaceView;
private CameraMaskView cameraRectView;
private TextView tvCancel;
private ImageView ivTake;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera);
findView();
initListener();
}
private void findView() {
tvCancel = findViewById(R.id.text_view_cancel);
ivTake = findViewById(R.id.image_view_take);
cameraSurfaceView = findViewById(R.id.camera_surface_view);
cameraRectView = findViewById(R.id.camera_rect_view);
}
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
// 設定中間預覽大小
cameraSurfaceView.setCenterMarkRect(cameraRectView.getCenterMarkRect());
}
private void initListener() {
tvCancel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
ivTake.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
cameraSurfaceView.takePicture();
}
});
cameraSurfaceView.setOnPathChangedListener(new CameraSurfaceView.OnPathChangedListener() {
@Override
public void onValueChange(String path) {
Toast.makeText(CameraActivity.this, path, Toast.LENGTH_SHORT).show();
}
});
}
}
複製程式碼