Android Studio | 直接调用系统摄像头拍照并回显、在SurfaceView中实现嵌入拍照并回显

1.直接调用系统摄像头拍照

功能实现:点击按钮,调用系统摄像头拍照之后,回显在imageviewl里面。
在这里插入图片描述

public class register extends AppCompatActivity
{
    private ImageView shotview ;//shotview定义在这里
    //【warning】如果这里写成:private ImageView shotview = findViewById(R.id.imageView);会报错
    //因为需要在onCreate()将类实例化之后,才可以进行初始化。
    private File currentImageFile = null;
    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.regiester);
        shotview = findViewById(R.id.imageView); //shotview的初始化在这里

        Button takePhoto = findViewById(R.id.getcamera);
        takePhoto.setOnClickListener(new View.OnClickListener()
        {
            //直接调用系统摄像头
            @Override
            public void onClick(View v)
            {
                //dir指的是directory,目录。storage directory 存储目录。

                //如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()
                //but!如果你的api 版本低于8,那么不能使用getExternalStoragePublicDirectory(),
                //而是使用Environment.getExternalStorageDirectory(),不带参数,不能自己创建一个目录,只是返回外部存储的根路径。
                File dir = new File(Environment.getExternalStorageDirectory(),"pictures");
                //函数原型:File newFile=new File(directory, filename)
                //创建了一个文件夹,名字是dir,路径是外部存储的根路径,名字是"pictures"。
                if(dir.exists())
                {
                    dir.mkdirs();//在根路径下建子目录,子目录名是"pictures"
                }

                //命名临时图片的文件名
                currentImageFile = new File(dir,System.currentTimeMillis() + ".jpg");
                if(!currentImageFile.exists())
                {
                    try
                    {
                        currentImageFile.createNewFile();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }

                Intent it = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//通过intent调用照相机照相
                it.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(currentImageFile));
                //存到外部存储的临时文件currentImageFile的路径下
                startActivityForResult(it, Activity.DEFAULT_KEYS_DIALER);
                //如果想在Activity中得到新打开Activity 关闭后返回的数据,
                // 需要使用系统提供的startActivityForResult(Intent intent, int requestCode)方法
                //打开新的Activity,新的Activity 关闭后会向前面的Activity传回数据,为了得到传回的数据,
                //必须在前面的Activity中重写onActivityResult(int requestCode, int resultCode, Intent data)方法。
            }
        });
    }
    //重写onActivityResult(int requestCode, int resultCode, Intent data)方法
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data)
    {
        if (requestCode == Activity.DEFAULT_KEYS_DIALER)
        {
            shotview.setImageURI(Uri.fromFile(currentImageFile));
        }
    }
}

关于内部存储与外部存储:

1、写一个相册程序,图片肯定是放在外部存储中;而如果要保存一个应用的一些设置数据,是放在内部存储的data目录下。因此其实在安卓文件管理中,我们都是在操作绝对路径。

2、如今的设备,很多中高端机器都将自己的机身存储扩展到了8G以上,他们将存储在概念上分成了"内部internal" 和"外部external" 两部分,但其实都在手机内部。所以不管安卓手机是否有可移动的sdcard,他们总是有外部存储和内部存储。
3、你把手机连接电脑,能被电脑识别的部分就一定是外部存储。
4、公共文件Public files:文件是可以被自由访问,且文件的数据对其他应用或者用户来说都是由意义的,当应用被卸载之后,其卸载前创建的文件仍然保留。
私有文件Private files:外部存储上,应用私有文件的价值在于卸载之后,这些文件也会被删除。
5、如果你想在外存储上放公共文件你可以使用getExternalStoragePublicDirectory()。but!如果你的api 版本低于8,那么不能使用getExternalStoragePublicDirectory(),而是使用Environment.getExternalStorageDirectory(),它不带参数,不能自己创建一个目录,只是返回外部存储的根路径。
【引用总结自:个人认为的一个关于内部存储和外部存储的很好的总结】

2.将拍照界面通过SurfaceView嵌入自己写的界面,存储拍下的照片,照片回调显示

在这里插入图片描述
其中关于surfaceView的设置:

<SurfaceView
        android:id="@+id/sfv_preview"
        android:layout_width="350dp"
        android:layout_height="393dp"
        android:text="@string/photo_preview"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.529"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.135" />

register.java中的代码如下:

public class register extends AppCompatActivity
{
        private SurfaceView sfv_preview;
        private Button btn_take_photo;
        private Camera camera = null;

        //surfaceHolder是surface的监听器,提供访问和控制SurfaceView背后的Surface 相关的方法
        private SurfaceHolder.Callback cpHolderCallback = new SurfaceHolder.Callback()
        {
            @Override
            public void surfaceCreated(SurfaceHolder holder)
            //当surface对象创建后,该方法就会被立即调用。
            {
                startPreview();
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
            //当surface发生任何结构性的变化时(格式或者大小),该方法就会被立即调用
            {
            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder)
            //当surface对象在将要销毁前,该方法会被立即调用。
            {
                stopPreview();
            }
        };

        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.regiester);
            bindViews();
        }

        private void bindViews()
        {
            sfv_preview = (SurfaceView) findViewById(R.id.sfv_preview);
            btn_take_photo = (Button) findViewById(R.id.getcamera);
            sfv_preview.getHolder().addCallback(cpHolderCallback);
            //获得sfv_preview的surfaceview,
            //再由 addCallback为SurfaceHolder添加一个SurfaceHolder.Callback回调接口。

            btn_take_photo.setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)//按下“开始拍照”按钮
                {
                    camera.takePicture(null, null, new Camera.PictureCallback()
                            //拍照函数
                    {
                        @Override
                        public void onPictureTaken(byte[] data, Camera camera)
                        {
                            String path = "";//定义路径
                            if ((path = saveFile(data)) != null)//如果路径存在
                            {
                                Intent it = new Intent(register.this, show_registered_photo.class);
                                it.putExtra("path", path);
                                startActivity(it);
                                //用intent实现从当前界面跳转到预览照片的界面
                            }
                            else
                            {
                                Toast.makeText(register.this, "保存照片失败", Toast.LENGTH_SHORT).show();
                            }
                        }
                    });
                }
            });
        }

        //保存临时文件的方法
        private String saveFile(byte[] bytes){
            try {
                File file = File.createTempFile("img","");
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(bytes);
                fos.flush();
                fos.close();
                return file.getAbsolutePath();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
            return "";
        }


        //开始预览
        private void startPreview()
        {
            camera = Camera.open();
            try
            {
                camera.setPreviewDisplay(sfv_preview.getHolder());
                camera.setDisplayOrientation(90);   //让相机旋转90度
                camera.startPreview();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }

        //停止预览
        private void stopPreview() {
            camera.stopPreview();
            camera.release();
            camera = null;
        }
}

3.1遇到的小插曲(1):

代码没有错的情况下,和camera有关的方法都报错。如下图所示:
在这里插入图片描述
在这里插入图片描述
后来发现是因为import了错误的包,关于Camera有两个不同的包,在快捷import的时候有两个选项,如下图(画×的是我之前调用的包,画√的是导入了之后就不再报错的包),导入的时候要多注意:
在这里插入图片描述

3.2 遇到的小插曲(2)

拍照界面跳出来之后,按下btn_take_photo按钮后闪退回登录界面。
报错原因:是因为show_registered_photo类没有注册,Alt+Enter快捷键,讲其写入 AndroidManifest.xml 即可。

代码参考链接:9.3 使用Camera拍照 | 菜鸟教程

可以使用 Element UI 的 Upload 组件来上传图片,然后在 Select 组件选择已上传的图片。具体步骤如下: 1. 引入 Element UI 和 Vue.js: ```html <!-- 引入 Element UI 样式 --> <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css"> <!-- 引入 Vue.js --> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <!-- 引入 Element UI 组件库 --> <script src="https://unpkg.com/element-ui/lib/index.js"></script> ``` 2. 创建一个 Vue 实例,并在模板添加 Select 组件和 Upload 组件: ```html <div id="app"> <el-select v-model="imageUrl" placeholder="请选择图片"> <el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value"> <img :src="item.value" alt="" style="width: 50px; height: 50px;"> </el-option> </el-select> <el-upload class="upload-demo" action="/upload" :on-success="handleSuccess" :show-file-list="false" :before-upload="beforeUpload"> <el-button size="small" type="primary">点击上传</el-button> </el-upload> </div> ``` 3. 在 Vue 实例定义数据和方法: ```js new Vue({ el: '#app', data() { return { options: [], // Select 组件的选项 imageUrl: '' // Select 组件选的图片地址 } }, methods: { // 上传成功后将图片地址添加到 Select 组件的选项 handleSuccess(response, file, fileList) { this.options.push({ label: file.name, value: response.url }) }, // 上传前校验文件类型和大小 beforeUpload(file) { const isJPG = file.type === 'image/jpeg' const isPNG = file.type === 'image/png' const isLt2M = file.size / 1024 / 1024 < 2 if (!(isJPG || isPNG)) { this.$message.error('上传图片只能是 JPG 或 PNG 格式!') } if (!isLt2M) { this.$message.error('上传图片大小不能超过 2MB!') } return isJPG || isPNG && isLt2M } } }) ``` 4. 在 handleSuccess 方法将上传成功的图片地址添加到 Select 组件的选项,然后在模板使用 img 标签显示图片即可。 这样就实现了使用 Select 组件选择已上传的图片并在 Select 框回显图片的功能。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值