Android 相机开发 Camera-附带扫码遮罩界面实现原理(自动聚焦)

  • Post author:
  • Post category:其他


相机遮罩实现原理,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

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <SurfaceView
            android:id="@+id/surfaceview"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <com.example.administrator.myapplication.view.ViewFinder
            android:id="@+id/viewfinder"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </FrameLayout>
</RelativeLayout>

注释写的挺详细的了,功能基本实现

福利

大牛的

CSDN

,参考他的也行



版权声明:本文为majiahuiCSDN原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。