Loading packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +187 −150 Original line number Diff line number Diff line Loading @@ -39,10 +39,10 @@ import com.android.systemui.util.animation.AnimationUtil.Companion.frames import javax.inject.Inject import kotlin.math.roundToInt /** * Controls the view for system event animations. */ class SystemEventChipAnimationController @Inject constructor( /** Controls the view for system event animations. */ class SystemEventChipAnimationController @Inject constructor( private val context: Context, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, private val contentInsetsProvider: StatusBarContentInsetsProvider, Loading @@ -57,14 +57,20 @@ class SystemEventChipAnimationController @Inject constructor( private var animationDirection = LEFT @VisibleForTesting var chipBounds = Rect() private val chipWidth get() = chipBounds.width() private val chipRight get() = chipBounds.right private val chipLeft get() = chipBounds.left private var chipMinWidth = context.resources.getDimensionPixelSize( R.dimen.ongoing_appops_chip_min_animation_width) private val dotSize = context.resources.getDimensionPixelSize( R.dimen.ongoing_appops_dot_diameter) private val chipWidth get() = chipBounds.width() private val chipRight get() = chipBounds.right private val chipLeft get() = chipBounds.left private var chipMinWidth = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_min_animation_width) private val dotSize = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter) // Use during animation so that multiple animators can update the drawing rect private var animRect = Rect() Loading @@ -83,42 +89,57 @@ class SystemEventChipAnimationController @Inject constructor( // Initialize the animated view val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation() currentAnimatedView = viewCreator(themedContext).also { currentAnimatedView = viewCreator(themedContext).also { animationWindowView.addView( it.view, layoutParamsDefault( if (animationWindowView.isLayoutRtl) insets.left else insets.right)) if (animationWindowView.isLayoutRtl) insets.left else insets.right ), ) it.view.alpha = 0f // For some reason, the window view's measured width is always 0 here, so use the // parent (status bar) it.view.measure( View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).width, AT_MOST), (animationWindowView.parent as View).width, AT_MOST, ), View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).height, AT_MOST)) (animationWindowView.parent as View).height, AT_MOST, ), ) updateChipBounds(it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()) updateChipBounds( it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation(), ) } } override fun onSystemEventAnimationBegin(): Animator { initializeAnimRect() val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply { val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply { startDelay = 7.frames duration = 5.frames interpolator = null addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float } } currentAnimatedView?.contentView?.alpha = 0f val contentAlphaIn = ValueAnimator.ofFloat(0f, 1f).apply { val contentAlphaIn = ValueAnimator.ofFloat(0f, 1f).apply { startDelay = 10.frames duration = 10.frames interpolator = null addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply { } val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply { startDelay = 7.frames duration = 23.frames interpolator = STATUS_BAR_X_MOVE_IN Loading @@ -131,42 +152,44 @@ class SystemEventChipAnimationController @Inject constructor( override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator { initializeAnimRect() val finish = if (hasPersistentDot) { val finish = if (hasPersistentDot) { createMoveOutAnimationForDot() } else { createMoveOutAnimationDefault() } finish.addListener(object : AnimatorListenerAdapter() { finish.addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { animationWindowView.removeView(currentAnimatedView!!.view) } }) } ) return finish } private fun createMoveOutAnimationForDot(): Animator { val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { duration = 9.frames interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } } val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply { val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply { startDelay = 9.frames duration = 20.frames interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } } val keyFrame1Height = dotSize * 2 val chipVerticalCenter = chipBounds.top + chipBounds.height() / 2 val height1 = ValueAnimator.ofInt(chipBounds.height(), keyFrame1Height).apply { val height1 = ValueAnimator.ofInt(chipBounds.height(), keyFrame1Height).apply { startDelay = 8.frames duration = 6.frames interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 Loading @@ -175,7 +198,8 @@ class SystemEventChipAnimationController @Inject constructor( } } val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply { val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply { startDelay = 14.frames duration = 15.frames interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 Loading @@ -186,13 +210,15 @@ class SystemEventChipAnimationController @Inject constructor( // Move the chip view to overlap exactly with the privacy dot. The chip displays by default // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself val moveOut = ValueAnimator.ofInt(0, dotSize).apply { val moveOut = ValueAnimator.ofInt(0, dotSize).apply { startDelay = 3.frames duration = 11.frames interpolator = STATUS_CHIP_MOVE_TO_DOT addUpdateListener { // If RTL, we can just invert the move val amt = if (animationDirection == LEFT) { val amt = if (animationDirection == LEFT) { animatedValue as Int } else { -(animatedValue as Int) Loading @@ -207,20 +233,25 @@ class SystemEventChipAnimationController @Inject constructor( } private fun createMoveOutAnimationDefault(): Animator { val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply { val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply { startDelay = 6.frames duration = 6.frames interpolator = null addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float } } val contentAlphaOut = ValueAnimator.ofFloat(1f, 0f).apply { val contentAlphaOut = ValueAnimator.ofFloat(1f, 0f).apply { duration = 5.frames interpolator = null addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } } val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { duration = 23.frames interpolator = STATUS_BAR_X_MOVE_OUT addUpdateListener { Loading @@ -238,8 +269,9 @@ class SystemEventChipAnimationController @Inject constructor( fun init() { initialized = true themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings) animationWindowView = LayoutInflater.from(themedContext) .inflate(R.layout.system_event_animation_window, null) as FrameLayout animationWindowView = LayoutInflater.from(themedContext).inflate(R.layout.system_event_animation_window, null) as FrameLayout // Matches status_bar.xml val height = themedContext.resources.getDimensionPixelSize(R.dimen.status_bar_height) val lp = FrameLayout.LayoutParams(MATCH_PARENT, height) Loading @@ -250,24 +282,28 @@ class SystemEventChipAnimationController @Inject constructor( // Use contentInsetsProvider rather than configuration controller, since we only care // about status bar dimens contentInsetsProvider.addCallback(object : StatusBarContentInsetsChangedListener { contentInsetsProvider.addCallback( object : StatusBarContentInsetsChangedListener { override fun onStatusBarContentInsetsChanged() { val newContentArea = contentInsetsProvider .getStatusBarContentAreaForCurrentRotation() val newContentArea = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation() updateDimens(newContentArea) // If we are currently animating, we have to re-solve for the chip bounds. If we're // If we are currently animating, we have to re-solve for the chip bounds. If // we're // not animating then [prepareChipAnimation] will take care of it for us currentAnimatedView?.let { updateChipBounds(it, newContentArea) // Since updateCurrentAnimatedView can only be called during an animation, we // Since updateCurrentAnimatedView can only be called during an animation, // we // have to create a dummy animator here to apply the new chip bounds val animator = ValueAnimator.ofInt(0, 1).setDuration(0) animator.addUpdateListener { updateCurrentAnimatedView() } animator.start() } } }) } ) } /** Announces [contentDescriptions] for accessibility. */ Loading @@ -283,9 +319,9 @@ class SystemEventChipAnimationController @Inject constructor( } /** * Use the current status bar content area and the current chip's measured size to update * the animation rect and chipBounds. This method can be called at any time and will update * the current animation values properly during e.g. a rotation. * Use the current status bar content area and the current chip's measured size to update the * animation rect and chipBounds. This method can be called at any time and will update the * current animation values properly during e.g. a rotation. */ private fun updateChipBounds(chip: BackgroundAnimatableView, contentArea: Rect) { // decide which direction we're animating from, and then set some screen coordinates Loading Loading @@ -316,7 +352,6 @@ class SystemEventChipAnimationController @Inject constructor( private fun initializeAnimRect() = animRect.set(chipBounds) /** * To be called during an animation, sets the width and updates the current animated chip view */ Loading @@ -324,7 +359,8 @@ class SystemEventChipAnimationController @Inject constructor( when (animationDirection) { LEFT -> { animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom) } else /* RIGHT */ -> { } else /* RIGHT */ -> { animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom) } } Loading @@ -340,38 +376,39 @@ class SystemEventChipAnimationController @Inject constructor( animRect.left, verticalCenter - (height.toFloat() / 2).roundToInt(), animRect.right, verticalCenter + (height.toFloat() / 2).roundToInt()) verticalCenter + (height.toFloat() / 2).roundToInt(), ) updateCurrentAnimatedView() } /** * To be called during an animation, updates the animation rect offset and updates the chip */ /** To be called during an animation, updates the animation rect offset and updates the chip */ private fun updateAnimatedBoundsX(translation: Int) { currentAnimatedView?.view?.translationX = translation.toFloat() } /** * To be called during an animation. Sets the chip rect to animRect */ /** To be called during an animation. Sets the chip rect to animRect */ private fun updateCurrentAnimatedView() { currentAnimatedView?.setBoundsForAnimation( animRect.left, animRect.top, animRect.right, animRect.bottom animRect.left, animRect.top, animRect.right, animRect.bottom, ) } } /** * Chips should provide a view that can be animated with something better than a fade-in */ /** Chips should provide a view that can be animated with something better than a fade-in */ interface BackgroundAnimatableView { val view: View // Since this can't extend View, add a view prop get() = this as View val contentView: View? // This will be alpha faded during appear and disappear animation get() = null val chipWidth: Int get() = view.measuredWidth fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) } Loading Loading
packages/SystemUI/src/com/android/systemui/statusbar/events/SystemEventChipAnimationController.kt +187 −150 Original line number Diff line number Diff line Loading @@ -39,10 +39,10 @@ import com.android.systemui.util.animation.AnimationUtil.Companion.frames import javax.inject.Inject import kotlin.math.roundToInt /** * Controls the view for system event animations. */ class SystemEventChipAnimationController @Inject constructor( /** Controls the view for system event animations. */ class SystemEventChipAnimationController @Inject constructor( private val context: Context, private val statusBarWindowControllerStore: StatusBarWindowControllerStore, private val contentInsetsProvider: StatusBarContentInsetsProvider, Loading @@ -57,14 +57,20 @@ class SystemEventChipAnimationController @Inject constructor( private var animationDirection = LEFT @VisibleForTesting var chipBounds = Rect() private val chipWidth get() = chipBounds.width() private val chipRight get() = chipBounds.right private val chipLeft get() = chipBounds.left private var chipMinWidth = context.resources.getDimensionPixelSize( R.dimen.ongoing_appops_chip_min_animation_width) private val dotSize = context.resources.getDimensionPixelSize( R.dimen.ongoing_appops_dot_diameter) private val chipWidth get() = chipBounds.width() private val chipRight get() = chipBounds.right private val chipLeft get() = chipBounds.left private var chipMinWidth = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_min_animation_width) private val dotSize = context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_dot_diameter) // Use during animation so that multiple animators can update the drawing rect private var animRect = Rect() Loading @@ -83,42 +89,57 @@ class SystemEventChipAnimationController @Inject constructor( // Initialize the animated view val insets = contentInsetsProvider.getStatusBarContentInsetsForCurrentRotation() currentAnimatedView = viewCreator(themedContext).also { currentAnimatedView = viewCreator(themedContext).also { animationWindowView.addView( it.view, layoutParamsDefault( if (animationWindowView.isLayoutRtl) insets.left else insets.right)) if (animationWindowView.isLayoutRtl) insets.left else insets.right ), ) it.view.alpha = 0f // For some reason, the window view's measured width is always 0 here, so use the // parent (status bar) it.view.measure( View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).width, AT_MOST), (animationWindowView.parent as View).width, AT_MOST, ), View.MeasureSpec.makeMeasureSpec( (animationWindowView.parent as View).height, AT_MOST)) (animationWindowView.parent as View).height, AT_MOST, ), ) updateChipBounds(it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation()) updateChipBounds( it, contentInsetsProvider.getStatusBarContentAreaForCurrentRotation(), ) } } override fun onSystemEventAnimationBegin(): Animator { initializeAnimRect() val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply { val alphaIn = ValueAnimator.ofFloat(0f, 1f).apply { startDelay = 7.frames duration = 5.frames interpolator = null addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float } } currentAnimatedView?.contentView?.alpha = 0f val contentAlphaIn = ValueAnimator.ofFloat(0f, 1f).apply { val contentAlphaIn = ValueAnimator.ofFloat(0f, 1f).apply { startDelay = 10.frames duration = 10.frames interpolator = null addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply { } val moveIn = ValueAnimator.ofInt(chipMinWidth, chipWidth).apply { startDelay = 7.frames duration = 23.frames interpolator = STATUS_BAR_X_MOVE_IN Loading @@ -131,42 +152,44 @@ class SystemEventChipAnimationController @Inject constructor( override fun onSystemEventAnimationFinish(hasPersistentDot: Boolean): Animator { initializeAnimRect() val finish = if (hasPersistentDot) { val finish = if (hasPersistentDot) { createMoveOutAnimationForDot() } else { createMoveOutAnimationDefault() } finish.addListener(object : AnimatorListenerAdapter() { finish.addListener( object : AnimatorListenerAdapter() { override fun onAnimationEnd(animation: Animator) { animationWindowView.removeView(currentAnimatedView!!.view) } }) } ) return finish } private fun createMoveOutAnimationForDot(): Animator { val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { val width1 = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { duration = 9.frames interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_1 addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } } val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply { val width2 = ValueAnimator.ofInt(chipMinWidth, dotSize).apply { startDelay = 9.frames duration = 20.frames interpolator = STATUS_CHIP_WIDTH_TO_DOT_KEYFRAME_2 addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } addUpdateListener { updateAnimatedViewBoundsWidth(animatedValue as Int) } } val keyFrame1Height = dotSize * 2 val chipVerticalCenter = chipBounds.top + chipBounds.height() / 2 val height1 = ValueAnimator.ofInt(chipBounds.height(), keyFrame1Height).apply { val height1 = ValueAnimator.ofInt(chipBounds.height(), keyFrame1Height).apply { startDelay = 8.frames duration = 6.frames interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_1 Loading @@ -175,7 +198,8 @@ class SystemEventChipAnimationController @Inject constructor( } } val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply { val height2 = ValueAnimator.ofInt(keyFrame1Height, dotSize).apply { startDelay = 14.frames duration = 15.frames interpolator = STATUS_CHIP_HEIGHT_TO_DOT_KEYFRAME_2 Loading @@ -186,13 +210,15 @@ class SystemEventChipAnimationController @Inject constructor( // Move the chip view to overlap exactly with the privacy dot. The chip displays by default // exactly adjacent to the dot, so we can just move over by the diameter of the dot itself val moveOut = ValueAnimator.ofInt(0, dotSize).apply { val moveOut = ValueAnimator.ofInt(0, dotSize).apply { startDelay = 3.frames duration = 11.frames interpolator = STATUS_CHIP_MOVE_TO_DOT addUpdateListener { // If RTL, we can just invert the move val amt = if (animationDirection == LEFT) { val amt = if (animationDirection == LEFT) { animatedValue as Int } else { -(animatedValue as Int) Loading @@ -207,20 +233,25 @@ class SystemEventChipAnimationController @Inject constructor( } private fun createMoveOutAnimationDefault(): Animator { val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply { val alphaOut = ValueAnimator.ofFloat(1f, 0f).apply { startDelay = 6.frames duration = 6.frames interpolator = null addUpdateListener { currentAnimatedView?.view?.alpha = animatedValue as Float } } val contentAlphaOut = ValueAnimator.ofFloat(1f, 0f).apply { val contentAlphaOut = ValueAnimator.ofFloat(1f, 0f).apply { duration = 5.frames interpolator = null addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } addUpdateListener { currentAnimatedView?.contentView?.alpha = animatedValue as Float } } val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { val moveOut = ValueAnimator.ofInt(chipWidth, chipMinWidth).apply { duration = 23.frames interpolator = STATUS_BAR_X_MOVE_OUT addUpdateListener { Loading @@ -238,8 +269,9 @@ class SystemEventChipAnimationController @Inject constructor( fun init() { initialized = true themedContext = ContextThemeWrapper(context, R.style.Theme_SystemUI_QuickSettings) animationWindowView = LayoutInflater.from(themedContext) .inflate(R.layout.system_event_animation_window, null) as FrameLayout animationWindowView = LayoutInflater.from(themedContext).inflate(R.layout.system_event_animation_window, null) as FrameLayout // Matches status_bar.xml val height = themedContext.resources.getDimensionPixelSize(R.dimen.status_bar_height) val lp = FrameLayout.LayoutParams(MATCH_PARENT, height) Loading @@ -250,24 +282,28 @@ class SystemEventChipAnimationController @Inject constructor( // Use contentInsetsProvider rather than configuration controller, since we only care // about status bar dimens contentInsetsProvider.addCallback(object : StatusBarContentInsetsChangedListener { contentInsetsProvider.addCallback( object : StatusBarContentInsetsChangedListener { override fun onStatusBarContentInsetsChanged() { val newContentArea = contentInsetsProvider .getStatusBarContentAreaForCurrentRotation() val newContentArea = contentInsetsProvider.getStatusBarContentAreaForCurrentRotation() updateDimens(newContentArea) // If we are currently animating, we have to re-solve for the chip bounds. If we're // If we are currently animating, we have to re-solve for the chip bounds. If // we're // not animating then [prepareChipAnimation] will take care of it for us currentAnimatedView?.let { updateChipBounds(it, newContentArea) // Since updateCurrentAnimatedView can only be called during an animation, we // Since updateCurrentAnimatedView can only be called during an animation, // we // have to create a dummy animator here to apply the new chip bounds val animator = ValueAnimator.ofInt(0, 1).setDuration(0) animator.addUpdateListener { updateCurrentAnimatedView() } animator.start() } } }) } ) } /** Announces [contentDescriptions] for accessibility. */ Loading @@ -283,9 +319,9 @@ class SystemEventChipAnimationController @Inject constructor( } /** * Use the current status bar content area and the current chip's measured size to update * the animation rect and chipBounds. This method can be called at any time and will update * the current animation values properly during e.g. a rotation. * Use the current status bar content area and the current chip's measured size to update the * animation rect and chipBounds. This method can be called at any time and will update the * current animation values properly during e.g. a rotation. */ private fun updateChipBounds(chip: BackgroundAnimatableView, contentArea: Rect) { // decide which direction we're animating from, and then set some screen coordinates Loading Loading @@ -316,7 +352,6 @@ class SystemEventChipAnimationController @Inject constructor( private fun initializeAnimRect() = animRect.set(chipBounds) /** * To be called during an animation, sets the width and updates the current animated chip view */ Loading @@ -324,7 +359,8 @@ class SystemEventChipAnimationController @Inject constructor( when (animationDirection) { LEFT -> { animRect.set((chipRight - width), animRect.top, chipRight, animRect.bottom) } else /* RIGHT */ -> { } else /* RIGHT */ -> { animRect.set(chipLeft, animRect.top, (chipLeft + width), animRect.bottom) } } Loading @@ -340,38 +376,39 @@ class SystemEventChipAnimationController @Inject constructor( animRect.left, verticalCenter - (height.toFloat() / 2).roundToInt(), animRect.right, verticalCenter + (height.toFloat() / 2).roundToInt()) verticalCenter + (height.toFloat() / 2).roundToInt(), ) updateCurrentAnimatedView() } /** * To be called during an animation, updates the animation rect offset and updates the chip */ /** To be called during an animation, updates the animation rect offset and updates the chip */ private fun updateAnimatedBoundsX(translation: Int) { currentAnimatedView?.view?.translationX = translation.toFloat() } /** * To be called during an animation. Sets the chip rect to animRect */ /** To be called during an animation. Sets the chip rect to animRect */ private fun updateCurrentAnimatedView() { currentAnimatedView?.setBoundsForAnimation( animRect.left, animRect.top, animRect.right, animRect.bottom animRect.left, animRect.top, animRect.right, animRect.bottom, ) } } /** * Chips should provide a view that can be animated with something better than a fade-in */ /** Chips should provide a view that can be animated with something better than a fade-in */ interface BackgroundAnimatableView { val view: View // Since this can't extend View, add a view prop get() = this as View val contentView: View? // This will be alpha faded during appear and disappear animation get() = null val chipWidth: Int get() = view.measuredWidth fun setBoundsForAnimation(l: Int, t: Int, r: Int, b: Int) } Loading