안드로이드 코틀린

[Kotlin][Android] 카메라로 찍은 사진 이미지 뷰에 띄워주기

teamnova 2021. 12. 3. 12:00
728x90

안녕하세요. 이번시간에는 코틀린으로 카메라로 이미지를 받아와 이미지 뷰에 띄워주는 기능을 구현해보도록 하겠습니다. 

 

개발 순서는 다음과 같습니다.

1. XML 파일 만들기

2. 권한 승인 요청하기

3. 권한 승인 시 카메라 실행

4. 카메라 실행후 결과 값을 받아 이미지뷰에 띄워주기.

 

1. XML 파일 만들기 (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity">

    <Button
        android:id="@+id/buttonCamera"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="24dp"
        android:text="카메라"
        android:textSize="24sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent" />

    <ImageView
        android:id="@+id/imagePreview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@+id/buttonCamera"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>

XML파일 작성시 보이는 화면

2. 권한 승인 요청하기

 

권한을 요청하기 전에 필요한 권한을 Manifest에 추가해주도록 합시다.

<uses-permission android:name="android.permission.CAMERA" />

카메라 버튼을 클릭했을 때 권한 요청을 하도록 아래와 같이 작성해줍시다.

 // 카메라 버튼 클릭 리스너 구현
 val cameraBtn = findViewById<Button>(R.id.buttonCamera) as Button
     cameraBtn.setOnClickListener(View.OnClickListener {
     requirePermissions(arrayOf(Manifest.permission.CAMERA), PERMISSION_CAMERA)
 })

 

아래는 권한을 요청하는 코드입니다.

/**자식 액티비티에서 권한 요청 시 직접 호출하는 메서드
     * @param permissions 권한 처리를 할 권한 목록
     * @param requestCode 권한을 요청한 주체가 어떤 것인지 구분하기 위함.
     * */
    fun requirePermissions(permissions: Array<String>, requestCode: Int) {
        Logger.d("권한 요청")
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            permissionGranted(requestCode)
        } else {
            // isAllPermissionsGranted : 권한이 모두 승인 되었는지 여부 저장
            // all 메서드를 사용하면 배열 속에 들어 있는 모든 값을 체크할 수 있다.
            val isAllPermissionsGranted =
                permissions.all { checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED }
            if (isAllPermissionsGranted) {
                permissionGranted(requestCode)
            } else {
                // 사용자에 권한 승인 요청
                ActivityCompat.requestPermissions(this, permissions, requestCode)
            }
        }
    }

권한을 요청하고 나서 사용자 반응에 따라 처리해야하는 로직을 아래와 같이 작성해줍시다.

그리고 권한이 승인 되었을 때 카메라가 켜지도록 합시다.

/** 사용자가 권한을 승인하거나 거부한 다음에 호출되는 메서드
     * @param requestCode 요청한 주체를 확인하는 코드
     * @param permissions 요청한 권한 목록
     * @param grantResults 권한 목록에 대한 승인/미승인 값, 권한 목록의 개수와 같은 수의 결괏값이 전달된다.
     * */
    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
            permissionGranted(requestCode)
        } else {
            permissionDenied(requestCode)
        }
    }

    private fun permissionGranted(requestCode: Int) {
        when (requestCode) {
            PERMISSION_CAMERA -> openCamera()
        }
    }

    private fun permissionDenied(requestCode: Int) {
        when (requestCode) {
            PERMISSION_CAMERA -> Toast.makeText(
                this,
                "카메라 권한을 승인해야 카메라를 사용할 수 있습니다.",
                Toast.LENGTH_LONG
            ).show()
        }
    }

카메라를 찍은 값을 Uri로 받기 위해 아래 와 같이 작성해줍니다.

private fun openCamera() {
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)

        createImageUri(newFileName(), "image/jpg")?.let { uri ->
            realUri = uri
            // MediaStore.EXTRA_OUTPUT을 Key로 하여 Uri를 넘겨주면
            // 일반적인 Camera App은 이를 받아 내가 지정한 경로에 사진을 찍어서 저장시킨다.
            intent.putExtra(MediaStore.EXTRA_OUTPUT, realUri)
            startActivityForResult(intent, REQUEST_CAMERA)
        }
    }

    private fun newFileName(): String {
        val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
        val filename = sdf.format(System.currentTimeMillis())
        return "$filename.jpg"
    }

    private fun createImageUri(filename: String, mimeType: String): Uri? {
        var values = ContentValues()
        values.put(MediaStore.Images.Media.DISPLAY_NAME, filename)
        values.put(MediaStore.Images.Media.MIME_TYPE, mimeType)
        return this.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
    }

카메라를 찍으면 다음과 같이 이미지를 Uri에 넣어주도록 합니다.

/** 카메라 및 앨범 Intent 결과
     * */
    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode == RESULT_OK) {
            when (requestCode) {
                REQUEST_CAMERA -> {
                    realUri?.let { uri ->
                        imageView.setImageURI(uri)
                    }
                }
            }
        }
    }

그러면 결과는 다음과 같이 나오게 됩니다.

 

코드 중간에 나오는 Logger 라이브러리는 스틱코드를 참고하시면 가져다 쓸 수 있습니다.

https://stickode.tistory.com/275

https://stickode.tistory.com/275