相机遮罩实现原理,FrameLayout中如果控件一样大,同一时间只能见到最上面的。
1.自定义ViewFindView,相机遮罩界面
public class ViewFinderView extends View {
//相机遮罩框外面的线,阴影区域,滚动线
private Paint border, area, line;
//相机遮罩框中间透明区域
private Rect center;
//屏幕大小
private int screenHeight, screenWidth;
//滚动线的起始点
private int startX, startY, endX, endY;
//滚动线向下滚动标识
private boolean isDown = true;
//滚动线速度
private static final int SPEED = 2;
//中间区域宽高(dp),
public static final int centerHeight = 300;
public static final int centerWidth = 300;
public ViewFinder(Context context) {
super(context);
}
public ViewFinder(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
//setAlpha一定要在setStyle后面,否则不起作用
border = new Paint(Paint.ANTI_ALIAS_FLAG);
border.setColor(Color.BLUE);
border.setStyle(Paint.Style.STROKE);
border.setStrokeWidth(5f);
border.setAlpha(10);
area = new Paint(Paint.ANTI_ALIAS_FLAG);
area.setStyle(Paint.Style.FILL);
area.setColor(Color.GRAY);
area.setAlpha(180);
screenHeight = DimenUtil.getScreenSize(context).heightPixels;
screenWidth = DimenUtil.getScreenSize(context).widthPixels;
center = getCenterRect(context, 300, 300);
line = new Paint(Paint.ANTI_ALIAS_FLAG);
line.setStyle(Paint.Style.STROKE);
line.setColor(Color.GREEN);
//设置滚动线的起始点
startX = center.left;
startY = center.top;
endX = center.right;
endY = center.top;
}
public ViewFinder(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
/**
* 根据尺寸获取中间区大小
*
* @param context
* @param height
* @param width
* @return
*/
private Rect getCenterRect(Context context, int height, int width) {
height = DimenUtil.px2dip(context, height);
width = DimenUtil.px2dip(context, width);
Rect rect = new Rect();
int left = (this.screenWidth - width) / 2;
int top = (this.screenHeight - height) / 2;
rect.set(left, top, left + width, top + height);
return rect;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//绘制四周阴影区域(上下左右),注意+1和-1,不设置不显示边框
canvas.drawRect(0, 0, screenWidth, center.top - 1, area);
canvas.drawRect(0, center.bottom + 1, screenWidth, screenHeight, area);
canvas.drawRect(0, center.top - 1, center.left - 1, center.bottom + 1, area);
canvas.drawRect(center.right + 1, center.top - 1, screenWidth, center.bottom + 1, area);
canvas.drawRect(center, border);
//滚动线
if (isDown) {
startY = endY += SPEED;
if (startY >= center.bottom)
isDown = false;
} else {
startY = endY -= SPEED;
if (startY <= center.top)
isDown = true;
}
canvas.drawLine(startX, startY, endX, endY, line);
postInvalidate();
}
}
2.DimenUtil
public class DimenUtil {
//dp转px
public static int dip2px(Context context, int dp) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (dp * density + 0.5f);
}
//px转dp
public static int px2dip(Context context, int px) {
float density = context.getResources().getDisplayMetrics().density;
return (int) (px / density + 0.5f);
}
//获取屏幕大小(px)
public static DisplayMetrics getScreenSize(Context context) {
return context.getResources().getDisplayMetrics();
}
}
3.主界面 MainActivity
public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback2, Camera.AutoFocusCallback, Camera.PreviewCallback, SensorEventListener {
private Camera camera;
private SurfaceHolder holder;
private SurfaceView surfaceView;
//传感器
private SensorManager manager;
//上次加速时间戳
private long lastTime;
//聚焦标识
private static boolean isFocusing;
//Android重力加速度传感器数据去噪
private float[] grivity = new float[3];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = findViewById(R.id.surfaceview);
//相机个数
int count = Camera.getNumberOfCameras();
//默认设置后置摄像头
if (count <= 0) {
Toast.makeText(this, "您的手机不支持相机", Toast.LENGTH_SHORT).show();
return;
} else if (count == 1) {
camera = Camera.open();
} else {
camera = Camera.open(0);
}
//设置旋转90度
camera.setDisplayOrientation(90);
Camera.Parameters parameters = camera.getParameters();
//设置自动聚焦模式
parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);
camera.setParameters(parameters);
camera.setPreviewCallback(this);
camera.autoFocus(this);
holder = surfaceView.getHolder();
holder.addCallback(this);
manager = (SensorManager) getSystemService(SENSOR_SERVICE);
}
@Override
public void surfaceRedrawNeeded(SurfaceHolder surfaceHolder) {
}
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
if (surfaceHolder.getSurface() == null)
return;
try {
camera.setPreviewDisplay(holder);
camera.startPreview();
//注册传感器
manager.registerListener(this, manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_UI);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
//取消传感器
manager.unregisterListener(this);
camera.stopPreview();
//这个必须加,否则报错Camera is being used after Camera.release() was called
camera.setPreviewCallback(null);
camera.release();
camera = null;
}
@Override
public void onAutoFocus(boolean b, Camera camera) {
if (b) {
isFocusing = false;
//连续聚焦必须加这段,每次聚焦成功之后取消自动聚焦
camera.cancelAutoFocus();
Toast.makeText(this, "聚焦成功", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
//此处用byte生成YuvImage,然后旋转90度,按照ViewFinderView中的centerHeight和centerWidth计算出中间框
//的位置,裁剪之后处理中间图片的数据(二维码,图片....)
}
@Override
public void onSensorChanged(SensorEvent sensorEvent) {
switch (sensorEvent.sensor.getType()) {
case Sensor.TYPE_ACCELEROMETER:
final float alpha = 0.8f;//为啥0.8我也不知道
grivity[0] = alpha * grivity[0] + (1 - alpha) * sensorEvent.values[0];
grivity[1] = alpha * grivity[1] + (1 - alpha) * sensorEvent.values[1];
grivity[2] = alpha * grivity[2] + (1 - alpha) * sensorEvent.values[2];
//取绝对值
float x = Math.abs(sensorEvent.values[0] - grivity[0]);
float y = Math.abs(sensorEvent.values[1] - grivity[1]);
float z = Math.abs(sensorEvent.values[2] - grivity[2]);
//获取当前时间戳
long current = System.currentTimeMillis();
if ((x + y + z) / 3 < 0.3 && !isFocusing && current - lastTime > 500 && current - lastTime < 1500) {
//相对静止并且不在聚焦,加速完成后500-1500ms之间进行聚焦
isFocusing = true;
camera.autoFocus(this);
} else if ((x + y + z) / 3 > 0.3) {
//相对正在加速
isFocusing = false;
lastTime = current;
}
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int i) {
//精度发生改变调用
}
}
4.activity_main.xml
注释写的挺详细的了,功能基本实现
福利
大牛的CSDN,参考他的也行