깐죽이의 정보 바다

안드로이드 코틀린 에니메이션 화면전환 효과 소스입니다. 리사이클뷰를 이용하여 카드뷰를 클릭 했을 경우 전환되는 화면에 에니메이션을 적용한 소스입니다. 

 

카드뷰로 리스트 목록을 보여주며 클릭시 상세 화면으로 넘어가는 액티비티 입니다. 

 

이미지는 패이드 효과를 주며 제목과 내용은 슬라이드로 위로 올라오는 화면전환 에니메이션입니다. 

 

리사이클뷰 화면전환

 

반응형

 

안드로이드 코틀린 리사이클뷰 에니메이션 화면전환 종속성설정

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
    id 'kotlin-parcelize'
}
dependencies {

    implementation 'androidx.core:core-ktx:1.10.1'
    implementation 'androidx.appcompat:appcompat:1.6.1'
    implementation 'com.google.android.material:material:1.9.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

    implementation "com.github.bumptech.glide:glide:4.11.0"

    implementation "androidx.recyclerview:recyclerview:1.3.0"

    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.5'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

데이터를 직렬화 하기 위해서 플러그인에 parcelize 플러그인을 추가합니다. 

 

반응형

 

안드로이드 코틀린 리사이클뷰 에니메이션 화면전환 소스설명

화면전환소스

internal class SingleTypeDiffCallback(
    private val viewBinder: ItemBinder
) : DiffUtil.ItemCallback<Any>() {

    override fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean {
        if(oldItem::class != newItem::class) {
            return false
        }
        return viewBinder?.areItemsTheSame(oldItem, newItem) ?: false
    }

    override fun areContentsTheSame(oldItem: Any, newItem:Any): Boolean {
        return viewBinder?.areContentsTheSame(oldItem, newItem) ?: false
    }

}

itemDiffCallback.kt 리사이클 데이터를 대조하여 클릭했을 경우 콜백하는 클래스입니다. 

 

class SingleViewBinderListAdapter(
    private val viewBinder: ItemBinder,
    stateRestorationPolicy: StateRestorationPolicy = StateRestorationPolicy.PREVENT_WHEN_EMPTY,
    private val recycleChildrenOnDetach: Boolean = false
) : ListAdapter<Any, ViewHolder>(SingleTypeDiffCallback(viewBinder)) {

    init {
        this.stateRestorationPolicy = stateRestorationPolicy
    }

    override fun getItemViewType(position: Int): Int =
        viewBinder.getItemLayoutResource()

    override fun onAttachedToRecyclerView(recyclerView: RecyclerView) {
        super.onAttachedToRecyclerView(recyclerView)
        if (recycleChildrenOnDetach) {
            val layoutManager = recyclerView.layoutManager
            (layoutManager as? LinearLayoutManager)?.recycleChildrenOnDetach = true
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
//        println("🔥 SingleViewBinderAdapter onCreateViewHolder() viewType: $viewType")
        return viewBinder.createViewHolder(parent)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
//        println("🤔 SingleViewBinderAdapter onBindViewHolder() position: $position, holder: $holder")
        viewBinder.bindViewHolder(currentList[position], holder)
    }

    override fun onViewRecycled(holder: ViewHolder) {
//        println("👻 SingleViewBinderAdapter onViewRecycled() holder: $holder")
        viewBinder.onViewRecycled(holder)
        super.onViewRecycled(holder)
    }

    override fun onViewDetachedFromWindow(holder: ViewHolder) {
//        println("💀 SingleViewBinderAdapter onViewDetachedFromWindow() holder $holder")
        viewBinder.onViewDetachedFromWindow(holder)
        super.onViewDetachedFromWindow(holder)
    }
}

SingleViewBinderListAdapter.kt  리사이클뷰 어댑터로 리소스 파일에서 itemBinder 를 가져와 묶는 작업입니다. 

typealias를 사용 하여 알리아스를 등록해서 추상 클래스를 사용했습니다. 

 

메인 액티비티에서 서브 액티비티로 화면전환 할때 사용하는 서브 액티비티 입니다. 

class Activity1_2Details : AppCompatActivity() {

    private val TAG = this.javaClass.simpleName
    private lateinit var binding: Activity12detailsBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = Activity12detailsBinding.inflate(layoutInflater)
        setContentView(binding.root)

        title = "카드뷰 변형 상세보기"

        postponeEnterTransition()

        val postCardModel = intent.extras?.getParcelable<PostCardModel>(KEY_POST_MODEL)

        postCardModel?.let {
            binding.ivPhoto.setImageResource(it.drawablesRes)
            binding.tvTitle.text = it.post.title
            binding.tvBody.text = it.post.body
        }

        setUpTransitions()
    }

    private fun setUpTransitions() {

        val transitions = TransitionSet()

        val transitionSetIvArcMove = TransitionInflater.from(this).
        inflateTransition(R.transition.activity2_detail_transition)

        transitionSetIvArcMove.interpolator = AccelerateDecelerateInterpolator()

        // Slide Transition with delay for texts
        val slide = createSlideTransition()
        transitions.addTransition(slide)

        // Fade Transition
        val fade: Transition = createFadeTransition()
        transitions.addTransition(fade)

        // Set Window transition for Shared transitions
        window.enterTransition = transitions

        // 🔥 Should be sharedElementEnterTransition NOT enterTransition
        window.sharedElementEnterTransition = transitionSetIvArcMove

        // Start postponed transition
        startPostponedEnterTransition()

    }

    private fun createSlideTransition() : Transition {
        val slide = Slide(Gravity.BOTTOM).apply {
            interpolator = AnimationUtils.loadInterpolator(
                this@Activity1_2Details,
                android.R.interpolator.linear_out_slow_in
            )
            startDelay = 200
            duration = 500
            addTarget(binding.tvTitle)
            addTarget(binding.tvBody)
        }

        // Add color change to Title after Slide Transition is complete
        slide.addListener(object : Transition.TransitionListener {

            override fun onTransitionStart(transition: Transition?) = Unit

            override fun onTransitionEnd(transition: Transition?) {

                val colorFrom = binding.tvTitle.currentTextColor
                val colorTo = Color.parseColor("#FF8F00")

                val colorAnimation: ValueAnimator =
                    ValueAnimator.ofObject(ArgbEvaluator(), colorFrom, colorTo)
                colorAnimation.addUpdateListener { animator ->
                    binding.tvTitle.setTextColor(animator.animatedValue as Int)
                }

                colorAnimation.duration = 200

                colorAnimation.start()
            }

            override fun onTransitionCancel(transition: Transition?) = Unit
            override fun onTransitionPause(transition: Transition?) = Unit
            override fun onTransitionResume(transition: Transition?) = Unit

        })

        return slide
    }

    private fun createFadeTransition() : Transition {
        val fade: Transition = Fade()
        val decor = window.decorView

        val view = decor.findViewById<View>(androidx.appcompat.R.id.action_bar_container)
        fade.excludeTarget(view, true)
        fade.excludeTarget(android.R.id.statusBarBackground, true)
        fade.excludeTarget(android.R.id.navigationBarBackground, true)
        return fade
    }

}

상단이미지는 패이드 효과를 주고 제목 부분은 색상변경과 컨텐츠 부분은 슬라이드 효과를 주는 소스입니다. 

 

class MainActivity : AppCompatActivity() {

    private val TAG = this.javaClass.simpleName
    private lateinit var listAdapter : SingleViewBinderListAdapter
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        title = "Ch1-2 리사이클뷰 에니메이션 변형"

        val postCardViewBinder = PostCardViewBinder {
            binding, postCardModel ->
            gotoDetailWithTransition(postCardModel, binding)
        }

        listAdapter = SingleViewBinderListAdapter(postCardViewBinder as ItemBinder)

        binding.recyclerView.apply {
            this.adapter = listAdapter
            layoutManager = LinearLayoutManager(this@MainActivity)
        }

         listAdapter.submitList(generateMockPosts())
        //setContentView(R.layout.activity_main)
    }

    /*
        액티비티 에니메이션 변형 바로가기 목록 함수
     */
    private fun gotoDetailWithTransition(
        postCardModel: PostCardModel,
        binding: ItemPostBinding
    ) {
        val intent = Intent(this@MainActivity, Activity1_2Details::class.java)

        intent.putExtra(KEY_POST_MODEL, postCardModel)

        // create the transition animation using image, title and body
        val pairIvAvatar = Pair<View, String>(binding.ivPhoto, binding.ivPhoto.transitionName)
        val pairTvTitle = Pair<View, String>(binding.tvTitle, binding.tvTitle.transitionName)
        val pairTvBody = Pair<View, String>(binding.tvBody, binding.tvBody.transitionName)

        val options = ActivityOptions
            .makeSceneTransitionAnimation(
                this,
//                pairTvTitle,
                pairIvAvatar
            )

        // start the new activity
        startActivity(intent, options.toBundle())
    }

    private fun generateMockPosts() : List<PostCardModel> {
        val postList = ArrayList<PostCardModel>()
        val random = Random()

        repeat(30) {
            val randomNum = random.nextInt(5)
            val title = "제목 $randomNum"
            val postBody = getString(R.string.bacon_ipsum)
            val post = Post(it, it, title, postBody)
            postList.add(PostCardModel(post, getDrawableRes(randomNum)))
        }

        return postList
    }

    private fun getDrawableRes(userId: Int): Int {
        return when {
            userId % 6 == 0 -> {
                R.drawable.avatar_1_raster
            }
            userId % 6 == 1 -> {
                R.drawable.avatar_2_raster
            }
            userId % 6 == 2 -> {
                R.drawable.avatar_3_raster
            }
            userId % 6 == 3 -> {
                R.drawable.avatar_4_raster
            }
            userId % 6 == 4 -> {
                R.drawable.avatar_5_raster
            }
            else -> {
                R.drawable.avatar_6_raster
            }
        }
    }

}

메인 액티비티로 리사이클뷰를 사용하여 리스트를 뿌려줍니다. 

 

반응형

 

 

 

[소스다운받기]

 

GitHub - makiball/ch1-2

Contribute to makiball/ch1-2 development by creating an account on GitHub.

github.com

 

[함께보면 좋은 정보]

 

 

안드로이드 코틀린 에니메이션 화면전환 효과 Ch1-1

안드로이드 코틀린 에니메이션 화면전환 효과 소스입니다. 안드로이드로 앱을 제작할때 액티비티에서 프레지먼트로 액티비티에서 액티비티로 화면이 전환할때 사용하는 에니메이션 화면전환

kimkkanjuk.tistory.com

 

 

안드로이드 코틀린 에니메이션 효과 넣기 Ch1-0

안드로이드 코틀린 에미메이션 효과 넣기 소스 입니다. 버튼에 따라 객체의 색상변환 또는 움직일수 있습니다. transition 폴더를 생성하고 에니메이션 객체 구현소스는 폴더 안에 놓고 만들었습

kimkkanjuk.tistory.com

 

반응형

공유하기

facebook twitter kakaoTalk kakaostory naver band shouturl