1 /* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.wallpaper.picker.customization.ui.view.animator 18 19 import android.animation.ValueAnimator 20 import androidx.core.animation.addListener 21 import androidx.core.animation.doOnEnd 22 import androidx.recyclerview.widget.DefaultItemAnimator 23 import androidx.recyclerview.widget.RecyclerView.State 24 import androidx.recyclerview.widget.RecyclerView.ViewHolder 25 import com.android.wallpaper.R 26 import com.android.wallpaper.picker.customization.ui.view.adapter.FloatingToolbarTabAdapter.TabViewHolder 27 28 class TabItemAnimator : DefaultItemAnimator() { 29 canReuseUpdatedViewHoldernull30 override fun canReuseUpdatedViewHolder(viewHolder: ViewHolder, payloads: MutableList<Any>) = 31 true 32 33 override fun recordPreLayoutInformation( 34 state: State, 35 viewHolder: ViewHolder, 36 changeFlags: Int, 37 payloads: MutableList<Any>, 38 ): ItemHolderInfo { 39 if (changeFlags == FLAG_CHANGED && payloads.isNotEmpty()) { 40 return when (payloads[0] as? Int) { 41 SELECT_ITEM -> TabItemHolderInfo(true) 42 UNSELECT_ITEM -> TabItemHolderInfo(false) 43 else -> super.recordPreLayoutInformation(state, viewHolder, changeFlags, payloads) 44 } 45 } 46 return super.recordPreLayoutInformation(state, viewHolder, changeFlags, payloads) 47 } 48 animateChangenull49 override fun animateChange( 50 oldHolder: ViewHolder, 51 newHolder: ViewHolder, 52 preLayoutInfo: ItemHolderInfo, 53 postLayoutInfo: ItemHolderInfo, 54 ): Boolean { 55 if (preLayoutInfo is TabItemHolderInfo) { 56 val viewHolder = newHolder as TabViewHolder 57 val iconSize = 58 viewHolder.itemView.resources.getDimensionPixelSize( 59 R.dimen.floating_tab_toolbar_tab_icon_size 60 ) 61 ValueAnimator.ofFloat( 62 if (preLayoutInfo.selectItem) 0f else 1f, 63 if (preLayoutInfo.selectItem) 1f else 0f, 64 ) 65 .apply { 66 addUpdateListener { 67 val value = it.animatedValue as Float 68 viewHolder.icon.layoutParams = 69 viewHolder.icon.layoutParams.apply { 70 width = (value * iconSize).toInt() 71 } 72 viewHolder.container.background.alpha = 73 (value * BACKGROUND_ALPHA_MAX).toInt() 74 } 75 addListener { doOnEnd { dispatchAnimationFinished(viewHolder) } } 76 duration = ANIMATION_DURATION_MILLIS 77 } 78 .start() 79 return true 80 } 81 82 return super.animateChange(oldHolder, newHolder, preLayoutInfo, postLayoutInfo) 83 } 84 85 class TabItemHolderInfo(val selectItem: Boolean) : ItemHolderInfo() 86 87 companion object { 88 const val SELECT_ITEM = 3024 89 const val UNSELECT_ITEM = 1114 90 const val BACKGROUND_ALPHA_MAX = 255 91 const val ANIMATION_DURATION_MILLIS = 200L 92 } 93 } 94