Last active
March 7, 2024 11:13
-
-
Save chrisbanes/b0db5e852035ab8c2a49803bac526019 to your computer and use it in GitHub Desktop.
Revisions
-
chrisbanes revised this gist
Jun 27, 2018 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,8 +14,6 @@ * limitations under the License. */ import android.animation.Animator import android.animation.AnimatorSet import android.animation.ObjectAnimator -
chrisbanes created this gist
Jun 27, 2018 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,57 @@ /* * Copyright 2018 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package app.tivi.ui.animations import android.animation.Animator import android.animation.AnimatorSet import android.animation.ObjectAnimator import android.graphics.ColorMatrixColorFilter import android.graphics.drawable.Drawable import android.support.v4.view.animation.FastOutSlowInInterpolator import android.view.View import androidx.core.animation.doOnEnd import kotlin.math.roundToLong private val fastOutSlowInInterpolator = FastOutSlowInInterpolator() fun saturateDrawableAnimator(current: Drawable, view: View): Animator { view.setHasTransientState(true) val cm = ImageLoadingColorMatrix() val duration = 1500L val satAnim = ObjectAnimator.ofFloat(cm, ImageLoadingColorMatrix.PROP_SATURATION, 0f, 1f) satAnim.duration = duration satAnim.interpolator = fastOutSlowInInterpolator satAnim.addUpdateListener { current.colorFilter = ColorMatrixColorFilter(cm) } val alphaAnim = ObjectAnimator.ofFloat(cm, ImageLoadingColorMatrix.PROP_ALPHA, 0f, 1f) alphaAnim.duration = duration / 2 alphaAnim.interpolator = fastOutSlowInInterpolator val darkenAnim = ObjectAnimator.ofFloat(cm, ImageLoadingColorMatrix.PROP_DARKEN, 0f, 1f) darkenAnim.duration = (duration * 0.75f).roundToLong() darkenAnim.interpolator = fastOutSlowInInterpolator val set = AnimatorSet() set.playTogether(satAnim, alphaAnim, darkenAnim) set.doOnEnd { current.clearColorFilter() view.setHasTransientState(false) } return set } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,52 @@ /* * Copyright 2018 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.graphics.drawable.Drawable import com.bumptech.glide.load.DataSource import com.bumptech.glide.request.transition.NoTransition import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.TransitionFactory class SaturationTransitionFactory : TransitionFactory<Drawable> { override fun build(dataSource: DataSource, isFirstResource: Boolean): Transition<Drawable> { return if (isFirstResource && dataSource != DataSource.MEMORY_CACHE) { // Only start the transition if this is not a recent load. We approximate that by // checking if the image is from the memory cache SaturationTransition() } else { NoTransition<Drawable>() } } } internal class SaturationTransition : Transition<Drawable> { override fun transition(current: Drawable, adapter: Transition.ViewAdapter): Boolean { saturateDrawableAnimator(current, adapter.view).also { it.start() } // We want Glide to still set the drawable return false } } @GlideExtension object GlideExtensions { @JvmStatic @GlideType(Drawable::class) fun saturateOnLoad(requestBuilder: RequestBuilder<Drawable>) { requestBuilder.transition(DrawableTransitionOptions.with(SaturationTransitionFactory())) } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,98 @@ /* * Copyright 2018 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.graphics.ColorMatrix /** * An extension to [ColorMatrix] which implements the Material image loading pattern */ class ImageLoadingColorMatrix : ColorMatrix() { private val elements = FloatArray(20) var saturationFraction = 1f set(value) { System.arraycopy(array, 0, elements, 0, 20) // Taken from ColorMatrix.setSaturation. We can't use that though since it resets the matrix // before applying the values val invSat = 1 - value val r = 0.213f * invSat val g = 0.715f * invSat val b = 0.072f * invSat elements[0] = r + value elements[1] = g elements[2] = b elements[5] = r elements[6] = g + value elements[7] = b elements[10] = r elements[11] = g elements[12] = b + value set(elements) } var alphaFraction = 1f set(value) { System.arraycopy(array, 0, elements, 0, 20) elements[18] = value set(elements) } var darkenFraction = 1f set(value) { System.arraycopy(array, 0, elements, 0, 20) // We substract to make the picture look darker, it will automatically clamp val darkening = (1 - value) * MAX_DARKEN_PERCENTAGE * 255 elements[4] = -darkening elements[9] = -darkening elements[14] = -darkening set(elements) } companion object { private val saturationFloatProp = object : FloatProp<ImageLoadingColorMatrix>("saturation") { override operator fun get(o: ImageLoadingColorMatrix): Float = o.saturationFraction override operator fun set(o: ImageLoadingColorMatrix, value: Float) { o.saturationFraction = value } } private val alphaFloatProp = object : FloatProp<ImageLoadingColorMatrix>("alpha") { override operator fun get(o: ImageLoadingColorMatrix): Float = o.alphaFraction override operator fun set(o: ImageLoadingColorMatrix, value: Float) { o.alphaFraction = value } } private val darkenFloatProp = object : FloatProp<ImageLoadingColorMatrix>("darken") { override operator fun get(o: ImageLoadingColorMatrix): Float = o.darkenFraction override operator fun set(o: ImageLoadingColorMatrix, value: Float) { o.darkenFraction = value } } val PROP_SATURATION = createFloatProperty(saturationFloatProp) val PROP_ALPHA = createFloatProperty(alphaFloatProp) val PROP_DARKEN = createFloatProperty(darkenFloatProp) // This means that we darken the image by 20% private const val MAX_DARKEN_PERCENTAGE = 0.20f } } This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,47 @@ /* * Copyright 2018 Google, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import android.os.Build import android.util.FloatProperty import android.util.Property /** * A delegate for creating a [Property] of `float` type */ abstract class FloatProp<T>(val name: String) { abstract operator fun set(o: T, value: Float) abstract operator fun get(o: T): Float } fun <T> createFloatProperty(impl: FloatProp<T>): Property<T, Float> { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { object : FloatProperty<T>(impl.name) { override fun get(o: T): Float = impl[o] override fun setValue(o: T, value: Float) { impl[o] = value } } } else { object : Property<T, Float>(Float::class.java, impl.name) { override fun get(o: T): Float = impl[o] override fun set(o: T, value: Float) { impl[o] = value } } } }