自定义相机(一)

本文详细介绍如何在Android应用中实现自定义相机功能,包括相机权限设置、预览界面搭建及SurfaceView与Camera类交互原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一步:拍照预览
第二步:相机参数设置、对焦实现、拍照存储在本地、拍照声音、闪光灯 自定义相机(二)

自定义相机(一)主要介绍,第一步拍照浏览功能的实现

主要涉及:
Camera类(注意是android.handware类下的,不是android.graphics类)(Camera2暂时不讨论)
SurfaceView类 SurfaceHolder类 SurfaceHolder.Callback回调接口

1.首先必需获取拍照需要的权限:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"></uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<uses-feature android:name="android.hardware.camera" />
2.接下来android的UI界面离不开Activity,所以我们创建个CameraActivity.java来显示相机
当然Camera类是必不可少的,它主要用来管理相机相关配置(闪光灯)和实现拍照功能
那SurfaceView又是干什么的呢?我们发现SurfaceView继承自View说明是视图,那就是用来显示
相机预览的。
SurfaceView做为相机专用View,为摄像等方法重写了很多方法,而且SurfaceView类会重新创建一个新的
单独线程绘制画面,而普通的View是在UI线程上绘制画面,我们知道UI线程阻塞超过5秒程序就会无响应,所以尽量
在子线程中执行消耗大的动作,带来良好的用户体验。


3.在写Activity之前先看看Google是如何继承重写SurfaceView的


public class CameraPreview extends SurfaceView implements SurfaceHolder.Callback {
    private SurfaceHolder mHolder;
    private Camera mCamera;

    public CameraPreview(Context context, Camera camera) {
        super(context);
        mCamera = camera;

        // Install a SurfaceHolder.Callback so we get notified when the
        // underlying surface is created and destroyed. 安装SurfaceHolder.Callback回调接口,
//以便SurfaceView 被创建和销毁时能及时得到通知(接口回调的本质是,给其他类能执行当前类重新实现的接口方法)
        mHolder = getHolder();

        mHolder.addCallback(this);
        // deprecated setting, but required on Android versions prior to 3.0
//已弃用的设置,但在3.0之前的Android版本上需要
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    public void surfaceCreated(SurfaceHolder holder) {
        // The Surface has been created, now tell the camera where to draw the preview.
// Surface已创建,现在告诉相机在哪里绘制预览
        try {
            mCamera.setPreviewDisplay(holder);
            mCamera.startPreview();
        } catch (IOException e) {
            Log.d(TAG, "Error setting camera preview: " + e.getMessage());
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        // empty. Take care of releasing the Camera preview in your activity.
//管理相机资源的释放
    }

    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
        // If your preview can change or rotate, take care of those events here.
        // Make sure to stop the preview before resizing or reformatting it.

      //如果您的预览可以更改或旋转,请在这里处理这些事件。
         //确保在调整大小或重新格式化之前停止预览。
        if (mHolder.getSurface() == null){
          // preview surface does not exist
          return;
        }

        // stop preview before making changes
        try {
            mCamera.stopPreview();
        } catch (Exception e){
          // ignore: tried to stop a non-existent preview
        }

        // set preview size and make any resize, rotate or
        // reformatting changes here
	/ /设置预览大小,并进行任何调整大小,旋转或
         / /重新格式化这里的变化

        // start preview with new settings
        try {
            mCamera.setPreviewDisplay(mHolder);
            mCamera.startPreview();

        } catch (Exception e){
            Log.d(TAG, "Error starting camera preview: " + e.getMessage());
        }
    }
}
4.SurfaceView已经完成,那怎么在Activity中使用呢?


public class CameraActivity extends Activity implements View.OnClickListener{

    Camera camera=null;
    private LinearLayout container;
    private ImageView iv_camera;
    private ImageView btn_camera;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//实现全屏,没有标题栏,也没有状态栏
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
        WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(R.layout.activity_camera);
        if (checkCameraHardware()){
            openCamera();
            initView();
        }else {
            Toast.makeText(this,"当前不支持相机!",Toast.LENGTH_SHORT).show();
        }

    }
    private void initView(){

        iv_camera=(ImageView) findViewById(R.id.iv_camera);
        btn_camera=(ImageView) findViewById(R.id.btn_camera);
        iv_camera.setOnClickListener(this);
        iv_camera.setOnClickListener(this);

    }
    //开始预览相机
    private void openCamera(){
        if (camera==null){
//获得相机实例
            camera=camera.open();
//注册容器控件
            container=(LinearLayout)findViewById(R.id.ll_contain);
//实例化SurfaceView
            CameraPreview cameraPreview=new CameraPreview(CameraActivity.this,camera);
            container.addView(cameraPreview);
        }
    }
    //释放相机资源
    private  void releaseCamera(){
        if (camera!=null){
            camera.setPreviewCallback(null);
            camera.stopPreview();
            camera.release();
            camera=null;
        }

    }
    // 判断相机是否支持
    private boolean checkCameraHardware() {
        if (this.getPackageManager().hasSystemFeature(
                PackageManager.FEATURE_CAMERA)) {
            return true;
        } else {
            return false;
        }
    }
//相机不使用时 释放资源
@Override
protected void onPause() {
    super.onPause();
    releaseCamera();
}

@Override
protected void onResume() {
    super.onResume();
    openCamera();
}
    @Override
    public void onClick(View v) {

    }
}
值得注意的是,android的相机只能被一个APP线程绑定,所以同一时间内,不能打开两个相机,我们用完相机时应该释放camera(Camera.release()来释放相机资源)


5.Activity的布局文件


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">


    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/ll_contain"
        android:orientation="horizontal"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </LinearLayout>
        <ImageView
            android:id="@+id/iv_camera"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:background="@drawable/ic_focusing_begin"/>

        <ImageView
            android:id="@+id/btn_camera"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            android:layout_marginBottom="10dp"
            android:src="@drawable/ic_bt"/>
    </RelativeLayout>
</LinearLayout>

运行程序发现(暂时没有拍照功能)有了拍照预览功能了,但是显示效果不佳,拍照方向不正确,尺寸不正确等
为什么会这样呢?自定义相机(二)我们将继续讲述...

自定义相机源码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值