코틀린 안드로이드 - 전자액자()

Jamwon·2021년 7월 5일
0

Kotlin_Android

목록 보기
16/30

저번에는 SAF를 이용해서 사진 추가하기를 누르면 핸드폰의 저장소에 접근하는것 까지 진행했다!

이제 그 사진을 가지고와서 액자화면을 구성하면 된다.
아! 애뮬레이터로 돌리시에 갤러리에 사진이 없기 때문에 사진을 추가해야된다!

사진 저장소에서 받아오기

startActivityForResult는 이동한 Acitivity에서 값을 가져와서 쓸때 사용한다. 따라서 전에 만들었던 startActivityForResult에서 사진(사진값)을 받아와서 MainActivity에서 사용!!

사진은 Uri값으로 받아온다.

onActivityResult() 함수

startActivityForResult에서 나온 결과를 onActivityResult() override 메소드에서 받을수 있다

우선 Uri값을 받아오기 때문에 이를 저장할 imageUrlList를 선언해준다.

private val imageUriList: MutableList<Uri> = mutableListOf() //초기화까지 같이

MainActivity.kt

  override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        if (resultCode != Activity.RESULT_OK) {
            return
        }
        when (requestCode) {
            2000 -> {
                val selectedImageUri: Uri? = data?.data
                if (selectedImageUri != null) {
                    if (imageUriList.size == 6) {
                        Toast.makeText(this, "이미 사진이 꽉찼습니다.", Toast.LENGTH_SHORT).show()
                        return
                    }
                    imageUriList.add(selectedImageUri)
                    imageViewList[imageUriList.size - 1].setImageURI(selectedImageUri)
                } else {
                    Toast.makeText(this, "사진을 가져오지 못했습니다", Toast.LENGTH_SHORT).show()
                }
            }
            else -> {
                // 다른 request일때 지금은 없음
                Toast.makeText(this, "사진을 가져오지 못했습니다.", Toast.LENGTH_SHORT).show()
            }
        }
    }

예외처리로 resultCode가 Acitivity.RESULT_OK가 아니면 문제가 생긴것이기 때문에 return 처리해준다.

위에서 startActivityForResult의 code를 2000으로 했기때문에 when문을 이용해서 reqeustCode가 2000이면 받은 data값을 nullcheck를 하면서 Uri변수에 넣어준다.

그리고 selectedImageUri를 imageUriList에 add해주고 그게 맞는 imageView의 이미지를 setImageURI() 함수를 이용해서 사진을 보이게 해준다!!

이전에 imageView를 6개만 만들었기 때문에 사진을 6개 넘게 추가하면 out of index 오류가 뜨기떄문에 imageUriList의 사이즈가 6이면 더이상 추가 할수 없게 return문 처리를 한다!

전자액자 Activity

imageView에 사진들이 추가되면 이제 전자액자 기능을 하는 액티비티를 만들어 준다. MainActivity파일이 있는 폴더에 생성!

액티비티를 생성했으면 AppCompatActivity()를 상속시켜주고 onCreate함수를 override 해주자.

액티비티를 생성하고 Manifest에 추가해주는거 잊지 말기!!!

액티비티를 생성했으니깐 그에 해당하는 layout도 만들어 주자.
res/layout 폴더에! activity_photoframe.xml로 생성!

activity_photoframe.xml

imageView 2개를 이용해서 전자액자 layout을 만든다 !

imageView가 2개 있을시 코드상에 밑에 있는데 위치로는 위에있는 imageView위에 존재한다.

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ImageView
        android:id="@+id/backgroundPhotoImageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="center"
        android:background="@color/black"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ImageView
        android:id="@+id/photoImageView"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:scaleType="center"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

initStartPhotoFrameModeButton()

MainActivity에서 끝내지 않은 함수.
Activity를 만들었기 때문에 저번에 완성하지 않은 전자액자 init함수를 만들자!

intent로 사진정보를 보내줘야하지만 Uri를 보낼수 없기떄문에 String형태로 보내야된다.

imageUriList.forEachIndexed{ index , uri->

을 사용하면 리스트의 index와 그에따른 uri를 각각 사용할 수 있다.

intent.putExtra 로 사진의 index와 uri.toString()으로 string형으로 바뀐 uri를 보내고 액티비티에서 몇번째 index까지 getExtra 해야하는지 알려주기 위해서 imageUriList의 size도 intent로 보내준다.

    private fun initStartPhotoFrameModeButton() {
        startPhotoFrameModeButton.setOnClickListener {
            val intent = Intent(this, PhotoFrameActivity::class.java)
            imageUriList.forEachIndexed { index, uri ->
                intent.putExtra("photo$index",uri.toString())
            }
            intent.putExtra("photoListSize",imageUriList.size)
            startActivity(intent)
        }
    }

PhotoFrameActivity.kt

intent로 넘어온 리스트 길이와 String Uri를 처리해준다.

getPhotoUriFromIntent()

    private fun getPhotoUriFromIntent(){
        val size = intent.getIntExtra("photoListSize",0)
        for (i in 0..size){
            intent.getStringExtra("photo$i")?.let {
                photoList.add(Uri.parse(it))
            }
        }
    }

받아온 list의 사이즈 만큼 for 문을 돌려서 미리 만들어놓은 photoList에 Uri를 추가해준다.

Uri.parse(it)

Uri.parse(Uri_string) 하면 String 문자열을 Uri형으로 변환할 수 있다. !!!

startTimer()

여기서는 5초마다 사진을 변경할거기 때문에 5초마다 특정 행동을 취하도록 함수를 만든다

timer의 period를 5000 (5초)으로 설정한다. 하지만 timer는 mainThread가 아니기 때문에 mainThread로 변환을 해줘야된다.

그리고 현재 몇번째 사진인지를 알려주는 전역변수를 선언한다.

private var currentPosition =0

ImageView.alpha = 0f -> 이미지뷰의 투명도 0이면 완전 투명해서 안보인다!

액티비티 life cycle

활동 수명주기 개념 공식 문서

생명주기!

문서를 꼭 읽어보자!

타이머 함수는 5초에 한번씩 타이머가 실행이된다.
하지만 어플이 백그라운드에 있을때 계속 실행이되면 안되기 때문에 timer를 on/off 할 수 있어야 된다.

어플리케이션이 백그라운드에 가있을때 onStop이상태이기 때문에 override된 onStop함수를 만들어서 타이머를 stop 해준다.

startTimer를 onCreate에서만 호출하면 onStop뒤에 다시 시작할때 onCreate는 실행되지 않기때문에 onStart에서 startTimer()를 실행시켜줘야된다.

화면 가로화면으로 보기

manifest에서

        <activity android:name=".PhotoFrameActivity"
            android:screenOrientation="landscape"
            />

이런식으로 activity에서 선언해주면 가로화면으로 액티비티가 실행된다.

android:screenOrientation="landscape"

PhotoFrameActivity.kt

class PhotoFrameActivity: AppCompatActivity() {

    private val photoList = mutableListOf<Uri>()

    private var currentPosition = 0

    private var timer: Timer? = null

    private val photoImageView: ImageView by lazy {
        findViewById<ImageView>(R.id.photoImageView)
    }

    private val backgroundPhotoImageView: ImageView by lazy {
        findViewById<ImageView>(R.id.backgroundPhotoImageView)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_photoframe)

        Log.d("PhotoFrame", "onCreate!!!")

        getPhotoUriFromIntent()
    }

    private fun getPhotoUriFromIntent() {
        val size = intent.getIntExtra("photoListSize", 0)
        for (i in 0..size) {
            intent.getStringExtra("photo$i")?.let {
                photoList.add(Uri.parse(it))
            }
        }
    }

    private fun startTimer() {
        timer = timer(period = 5 * 1000) {
            runOnUiThread {

                Log.d("PhotoFrame", "5초가 지나감 !!")

                val current = currentPosition
                val next = if (photoList.size <= currentPosition + 1) 0 else currentPosition + 1

                backgroundPhotoImageView.setImageURI(photoList[current])

                photoImageView.alpha = 0f
                photoImageView.setImageURI(photoList[next])
                photoImageView.animate()
                    .alpha(1.0f)
                    .setDuration(1000)
                    .start()

                currentPosition = next
            }

        }
    }

    override fun onStop() {
        super.onStop()

        Log.d("PhotoFrame", "onStop!!! timer cancel")
        timer?.cancel()
    }


    override fun onStart() {
        super.onStart()

        Log.d("PhotoFrame", "onStart!!! timer start")
        startTimer()
    }

    override fun onDestroy() {
        super.onDestroy()

        Log.d("PhotoFrame", "onDestroy!!! timer cancel")
        timer?.cancel()
    }



}

결과 화면


사진이 잘 나온다!
논현 진정성카페 좋다

새로 배운것

URI(Uniform Resuorce Identifier)

인터넷에 있는 자원을 나타내는 유일한 주소!

프로토콜+:+//+호스트이름+주소 로 이루어져있으며
비디오,사운드, 프로그램, 텍스트 등등 모든것들을 인식하기 위한 수단이다

String을 Uri.parse(string문자열) 하면 Uri로 형변환 가능

애니매이션

view에서 animate() 함수를 사용

alpha / rotate /translation 등 여러 기능이있다.

photoImageView.animate()
.alpha(1.0f) 불투명
.setDuration(1000) 1초에거쳐서
.start()

SAF

앞글에서 !!!

startActivityForResult

액티비티와 액티비티 끼리 data를 주고받기 위해서 사용된다.
startAcivityForResult(intent, 2000)
2000은 requestCode

위에서의 Result는 onActivityResult라는 함수로 받을수있다.

layout 가로화면으로 그리기

manifest에서 해당 activity에
android:screenOrientation="landscape" 값을 주면 액티비티가 실행될때 가로화면으로 실행이된다.

강제 가로나 세로화면을 지정할때 유용할듯!

activity life cycle

onCreate / onStop / onDestory 등등 어플이 꺼져있을때 등등의 상태에서 수행할수 있다.

잘알아두자 !

전자액자 끝!! 시간이 나면 사진 삭제 기능도 넣으면 좋을거같다

profile
한걸음씩 위로 자유롭게

0개의 댓글