[Android / Kotlin] makeSceneTransitionAnimation

Subeen·2023년 12월 28일
1

Android

목록 보기
26/73

어제(SNS 앱 팀 프로젝트 (1))에 이어 오늘도 메인 화면을 구현했다. 메인 화면에서 캐릭터를 클릭하여 디테일 화면으로 이동할 시 animation을 적용하는 부분을 추가했다.
kotlin animation을 검색하면 가장 많이 나오는 함수는 overridePendingTransition인데 해당 함수는 deprecated 되었다고 표시되어 다른 것을 찾던 중 makeSceneTransitionAnimation을 알게 되었다. makeSceneTransitionAnimation를 적용한 내용을 정리하고자 한다.

makeSceneTransitionAnimation

  • AnimationOptions의 하위 메서드인 makeSceneTransitionAnimation는 Transition이 발생할 때 전환 할 액티비티와 전환 되어질 액티비티에서 두 View를 연결하여 Animation을 지정해주는 기능이다.

메인 화면 구현

theme.xml

  • theme.xml에 Animation 사용 설정을 해준다.
<item name="android:windowActivityTransitions">true</item>

MainActivity


class MainActivity : AppCompatActivity() {

    private val rcCharacter: RecyclerView by lazy { findViewById(R.id.rcCharacter) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        initView()
    }

    private fun initView() {
        val items = CharacterManager.getItems().sortedBy { it.korName }

        val adapter = RecyclerCharacterAdapter(items)
        rcCharacter.adapter = adapter
        rcCharacter.layoutManager = GridLayoutManager(this, 3)

        adapter.setItemClickListener(object : RecyclerCharacterAdapter.OnItemClickListener {
            override fun onItemClick(view: View, position: Int) {
                showToast("$position")
                startDetailActivity(view, position)
            }
        })
    }

    private fun showToast(message: String) {
        Toast.makeText(applicationContext, message, Toast.LENGTH_SHORT).show()
    }

    private fun startDetailActivity(view: View, position: Int) {
        val intent = Intent(this, DetailActivity::class.java).apply {
            putExtra(characterId, position)
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }

        val transitionPairs = getTransitionPairs(view)
        /*
        Activity 전환 옵션을 설정한다. 
        ImageView, TextView 두개의 View를 등록하였다. 
        */
        val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
            this, *transitionPairs.toTypedArray()
        )

		// 인텐트에 Activity 옵션을 추가한다. 
        startActivity(intent, options.toBundle())
    }

    private fun getTransitionPairs(view: View): List<Pair<View, String>> {
        val characterPair = Pair<View, String>(view.findViewById(R.id.ivCharacter), "transImage")
        val characterNamePair =
            Pair<View, String>(view.findViewById(R.id.tvCharacterName), "transName")

        return listOf(characterPair, characterNamePair)
    }
}

RecyclerCharacterAdapter


class RecyclerCharacterAdapter(private val items: List<Character>) :
    RecyclerView.Adapter<RecyclerCharacterAdapter.ViewHolder>() {

    interface OnItemClickListener {
        fun onItemClick(view: View, position: Int)
    }

    private lateinit var listener: OnItemClickListener

    fun setItemClickListener(itemClickListener: OnItemClickListener) {
        listener = itemClickListener
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val itemView = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_rv_character, parent, false)
        return ViewHolder(itemView)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bindItem(items[position])
    }

    override fun getItemCount(): Int = items.size

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bindItem(item: Character) {
            val ivCharacter: ImageView = itemView.findViewById(R.id.ivCharacter)
            val tvName: TextView = itemView.findViewById(R.id.tvCharacterName)
            val tvComment: TextView = itemView.findViewById(R.id.tvCharacterComment)

            with(ivCharacter) {
                setImageResource(item.profileImage)
                clipToOutline = true
            }

            tvName.text = item.korName
            val commentsSize = "댓글 ${item.korName.getSize()}"
            tvComment.text = commentsSize

            itemView.setOnClickListener {
                val position = adapterPosition
                if (position != RecyclerView.NO_POSITION) {
                    listener.onItemClick(itemView, position)
                }
            }
        }
    }

    private fun String.getSize() = MyCommentsTempDatas().getCommentSize(this)
}

activity_main.xml

transitionAnimation을 등록하기 위해 key형태의 String 값을 View에 등록해주며 전환 할 액티비티와 전환 되어질 액티비티의 layout에 동일한 이름으로 등록한다.

android:transitionName="transImage" 
android:transitionName="transName"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="wrap_content"
    android:layout_margin="5dp"
    android:orientation="vertical">

    <ImageView
        android:id="@+id/ivCharacter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:adjustViewBounds="true"
        android:background="@drawable/iv_background_radius"
        android:transitionName="transImage" />

    <TextView
        android:id="@+id/tvCharacterName"
        style="@style/ThemeTvCharacter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="18sp"
        android:textStyle="bold"
        android:transitionName="transName" />

    <TextView
        android:id="@+id/tvCharacterComment"
        style="@style/ThemeTvCharacter"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textSize="13sp" />

</LinearLayout>

activity_detail.xml

android:transitionName="transImage"
android:transitionName="transName"
	...
	<ImageView
		android:id="@+id/profileImage"
		android:layout_width="150dp"
		android:layout_height="150dp"
		 android:src="@drawable/hawkeye"
		android:transitionName="transImage" />

	<LinearLayout
		android:layout_width="match_parent"
		android:layout_height="match_parent"
		android:orientation="vertical">

		<TextView
			android:id="@+id/korName"
			android:layout_width="wrap_content"
			android:layout_height="wrap_content"
			android:textSize="24dp"
			android:textStyle="bold"
			android:transitionName="transName"
			app:layout_constraintBottom_toBottomOf="@+id/img_hawk"
			app:layout_constraintStart_toEndOf="@+id/img_hawk"
			app:layout_constraintTop_toTopOf="@+id/img_hawk" />
	...

결과 화면

참조
Transition - 자연스러운 화면 연결 애니메이션

profile
개발 공부 기록 🌱

1개의 댓글

comment-user-thumbnail
2024년 1월 2일

공부가 됐습니다 감사합니다~

답글 달기