Fragment 트랜지션 쉽게 적용하기

2018-03-19
 

이 글은 Fragment에서 멋진 전환 효과를 적용하기 위한 글로 간단하지만 알아두면 쉽게 적용 할 수 있는 부분에 대해 다루려고 합니다. 얼마전 Chris Banes가 좀 더 멋진 장면 효과를 구현한 ColumnedChangeBounds 코드도 공개하였기 때문에 어떻게 사용할 수 있을지에 대해 알아 보겠습니다.

일반적으로 Fragment전환시 아무런 전환 효과를 주지 않습니다. commit과 동시에 컨텐츠 화면이 심심하게 바뀝니다. Fragment도 Activity에서 처럼 전환 효과를 주기위해서는 sharedElementViews를 이용하여 전환하고 싶은 View를 추가하면 됩니다. 그리고 트랜잭션 최적화 작업을 위해 etReorderingAllowed()속성을 허용합니다.

supportFragmentManager.beginTransaction()
  .setReorderingAllowed(true)
  .replace(R.id.container, GridFragment.newInstance(count))
  .addToBackStack("detail")
  .apply {
      val topFragment: Int = supportFragmentManager.fragments.size
      val fragment: GridFragment = supportFragmentManager.fragments[topFragment - 1] as GridFragment

      val recyclerView: RecyclerView = fragment.recyclerview

      var viewCount = 0
      for (itemView in recyclerView.children) {
          addSharedElement(itemView, viewCount.toString())
          viewCount++
      }

  }
  .commit()

위의 코드에서 addSharedElement를 통해 현재 보여지고 있는 View에 각각 전환될 이름을 부여 해줍니다. 그럼 Fragment가 전환된 View에 해당 전환된 이름의 View를 찾아 트랜지션 됩니다.


문제점

새로운 Fragment가 생성되면 데이터를 가져오거나 이미지를 불러오고 레이아웃을 구성하고 그리는 시간이 걸리기 때문에 전환 효과는 자연스럽지 않습니다. 이런 구성을 하는 동안 애니메이션이 끝나게 되는 경우 아무런 효과를 보지 못할 수 있습니다. 그렇기 때문에 장면 효과를 데이터나 뷰를 구성하기 전까지 지연할 필요가 있습니다.

postponeEnterTransition(), startPostponedEnterTransition()을 이용하면 장면 효과를 지연하고 시작할 수 있습니다. 우리는 뷰가 그려진다는 사실을 OnPreDrawListener를 통해 인지 할 수 있습니다. 최근에 지원된 코틀린 라이브러리 KTX를 이용한다면 OnPreDrawListener대신 doOnPreDraw를 통해 쉽게 콜백 받을 수 있습니다.

postponeEnterTransition()
 
recyclerView.doOnPreDraw {
    startPostponedEnterTransition()


이제 Fragment 전환 효과를 위한 준비는 모두 끝났습니다. 어떻게 트랜지션이 이루어 질지에 대한 정의만 해주면 되는데 기본적으로 몇가지를 지원해는데 Bounds가 변경되기 때문에 ChangeBounds() 트랜지션을 설정 하도록 하겠습니다.

override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      sharedElementEnterTransition = ChangeBounds()
}


좀 더 멋진 효과를 보기위해서는 Chris Banes과 같이 ColumnedChangeBounds를 직접 구현하면 됩니다. 이 글에서 구현된 모든 코드는 https://github.com/kmshack/FragmentTransitions에 공개됩니다.