[Android] MotionLayout.setTransitionListener 이벤트 후 UI 작동안하는 에러

park_sujeong·2022년 9월 1일
0

Errors

목록 보기
4/5

에러

MotionLayout의 setTransitionListener를 사용한 후 UI가 안보이는 에러가 발생했다. UI가 안보일뿐만 아니라 해당 UI의 기능들도 작동하지않았다.

구현하고자 했던 기능은 Fragment에서 MotionLayout의 이벤트가 발생할때 MainActivity의 MotionLayout의 이벤트도 일어나게 하는 것이었다.

아래 코드가 setTransitionListener를 사용했을 때 에러가 났던 코드다.


Fragment.kt


        binding.motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
            override fun onTransitionStarted(
                motionLayout: MotionLayout?,
                startId: Int,
                endId: Int
            ) {
            }

            override fun onTransitionChange(
                motionLayout: MotionLayout?,
                startId: Int,
                endId: Int,
                progress: Float
            ) {
                // MainActivity 모션 레이아웃에 값을 전달
                binding.let {
                    (activity as MainActivity).also { mainActivity ->
                        mainActivity.findViewById<MotionLayout>(mainBinding.mainMotionLayout.id).progress = abs(progress)
                    }
                }
            }

            override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {

            }

            override fun onTransitionTrigger(
                motionLayout: MotionLayout?,
                triggerId: Int,
                positive: Boolean,
                progress: Float
            ) {
            }

        })





원인

fragment에서 일어난 transition은 완료가 되었지만, fragment에서 호출한 MainActivity에서의 transition이 완료가 안되었기에 발생한 에러다.

확인하기 위해서 각 motionLayout에 setTransitionListener를 달아주고 로그로 transition이 제대로 종료되는지 확인해본다.

아래 코드는 데이터바인딩된 MainActivity에 쓴 코드다.


MainActivity.kt

      binding.mainMotionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
            override fun onTransitionStarted(
                motionLayout: MotionLayout?,
                startId: Int,
                endId: Int
            ) {
                Log.d("MainActivity", "onTransitionStarted")
            }

            override fun onTransitionChange(
                motionLayout: MotionLayout?,
                startId: Int,
                endId: Int,
                progress: Float
            ) {
                Log.d("MainActivity", "onTransitionChange")

            }

            override fun onTransitionCompleted(motionLayout: MotionLayout?, currentId: Int) {
                Log.d("MainActivity", "onTransitionCompleted")

            }

            override fun onTransitionTrigger(
                motionLayout: MotionLayout?,
                triggerId: Int,
                positive: Boolean,
                progress: Float
            ) {
                Log.d("MainActivity", "onTransitionTrigger")

            }

        })





해결

해결하는 방법은 MainActivity의 MotionLayout transition을 호출하는 Fragment의 MotionLayout setTransitionListener에서 호출한 MAinActivity의 transition을 임의로 종료해주는 것이다.

다양한 방법이 있겠지만, 나는 Fragment의 setTransitionListener에서 상속받은 onTransitionCompleted()에서 transition의 process를 동일하게 해주었다.

아래 코드가 위 내용으로 해결한 부분이다.

이렇게 한 이유는 MainActivity와 Framgnet의 transition의 start와 end의 같아야했기 때문이다. 이런게 필요없다면 transitionToStart()transitionToEnd()를 onTransitionCompleted에 넣어줘도 된다.


Fragment.kt


        binding.motionLayout.setTransitionListener(object : MotionLayout.TransitionListener {
            override fun onTransitionStarted(
                motionLayout: MotionLayout?,
                startId: Int,
                endId: Int
            ) {
                Log.d(TAG, "onTransitionStarted")
            }

            override fun onTransitionChange(
                motionLayout: MotionLayout?,
                startId: Int,
                endId: Int,
                progress: Float
            ) {
                // MainActivity 모션 레이아웃에 값을 전달
                binding.let {
                    // Fragment 는 자기 단독으로 존재할 수 없기 때문에 activity가 존재할 수밖에 없고
                    // Activity를 가져오면 해당 Fragment가 attacj 되어있는 액티비티를 가져온다.
                    (activity as MainActivity).also { mainActivity ->
                        mainActivity.findViewById<MotionLayout>(R.id.main_motion_layout).progress = abs(progress)
                    }
                }
                Log.d(TAG, "onTransitionChange")

            }

            override fun onTransitionCompleted(motionLayout: MotionLayout, currentId: Int) {
                (activity as MainActivity).also { mainActivity ->
                    mainActivity.findViewById<MotionLayout>(mainBinding.mainMotionLayout.id).progress = motionLayout.progress
                }
                Log.d(TAG, "SoundPlayerFragment : ${binding.motionLayout.currentState}," +
                        "MainActivity : ${(activity as MainActivity).also { mainActivity -> mainActivity.findViewById<MotionLayout>(mainBinding.mainMotionLayout.id).currentState }}")
            }

            override fun onTransitionTrigger(
                motionLayout: MotionLayout?,
                triggerId: Int,
                positive: Boolean,
                progress: Float
            ) {
                Log.d(TAG, "onTransitionTrigger")
            }

        })





profile
Android Developer

0개의 댓글