Skip to content
This repository was archived by the owner on Nov 21, 2024. It is now read-only.

Commit 2677e7b

Browse files
committed
Animate container color during transition.
Change-Id: I6f010fec4c74d3317a228aaf6c5bb82a4049a317
1 parent 5fdf0ae commit 2677e7b

File tree

3 files changed

+75
-27
lines changed

3 files changed

+75
-27
lines changed

app/src/main/java/com/materialstudies/owl/util/AnimationUtils.kt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ fun lerp(
5555
from = 0.0,
5656
fromInclusive = true,
5757
to = 1.0,
58-
toInclusive = false
58+
toInclusive = true
5959
) startFraction: Float,
60-
@FloatRange(from = 0.0, fromInclusive = false, to = 1.0, toInclusive = true) endFraction: Float,
60+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) endFraction: Float,
6161
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) fraction: Float
6262
): Float {
6363
if (fraction < startFraction) return startValue
@@ -76,9 +76,9 @@ fun lerp(
7676
from = 0.0,
7777
fromInclusive = true,
7878
to = 1.0,
79-
toInclusive = false
79+
toInclusive = true
8080
) startFraction: Float,
81-
@FloatRange(from = 0.0, fromInclusive = false, to = 1.0, toInclusive = true) endFraction: Float,
81+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) endFraction: Float,
8282
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) fraction: Float
8383
): Int {
8484
if (fraction < startFraction) return startValue
@@ -97,9 +97,9 @@ fun lerp(
9797
from = 0.0,
9898
fromInclusive = true,
9999
to = 1.0,
100-
toInclusive = false
100+
toInclusive = true
101101
) startFraction: Float,
102-
@FloatRange(from = 0.0, fromInclusive = false, to = 1.0, toInclusive = true) endFraction: Float,
102+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) endFraction: Float,
103103
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) fraction: Float
104104
): CornerRounding {
105105
if (fraction < startFraction) return startValue
@@ -164,9 +164,9 @@ fun lerpArgb(
164164
from = 0.0,
165165
fromInclusive = true,
166166
to = 1.0,
167-
toInclusive = false
167+
toInclusive = true
168168
) startFraction: Float,
169-
@FloatRange(from = 0.0, fromInclusive = false, to = 1.0, toInclusive = true) endFraction: Float,
169+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) endFraction: Float,
170170
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true) fraction: Float
171171
): Int {
172172
if (fraction < startFraction) return startColor

app/src/main/java/com/materialstudies/owl/util/ViewExtensions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ fun View.descendantBackgroundColor(): Int {
125125
}
126126
}
127127
}
128-
return context.themeColor(R.attr.colorSurface)
128+
return context.themeColor(android.R.attr.colorBackground)
129129
}
130130

131131
@ColorInt

app/src/main/java/com/materialstudies/owl/util/transition/MaterialContainerTransition.kt

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import android.graphics.drawable.Drawable
3131
import android.util.Property
3232
import android.view.ViewGroup
3333
import androidx.annotation.ColorInt
34+
import androidx.annotation.FloatRange
3435
import androidx.annotation.IdRes
3536
import androidx.annotation.Px
3637
import androidx.core.animation.doOnEnd
@@ -52,20 +53,31 @@ import com.materialstudies.owl.util.lerp
5253
import com.materialstudies.owl.util.lerpArgb
5354
import com.materialstudies.owl.util.toCornerRounding
5455
import com.materialstudies.owl.util.transition.MaterialContainerTransitionDrawable.PROGRESS
56+
import kotlin.math.roundToInt
5557

5658
@Px
5759
private const val BITMAP_PADDING_BOTTOM = 1
5860
private const val PROP_BOUNDS = "materialContainerTransition:bounds"
5961
private const val PROP_BITMAP = "materialContainerTransition:bitmap"
6062
private const val PROP_SHAPE_APPEARANCE = "materialContainerTransition:shapeAppearance"
61-
private val TRANSITION_PROPS = arrayOf(PROP_BOUNDS, PROP_BITMAP, PROP_SHAPE_APPEARANCE)
63+
private const val PROP_CONTAINER_COLOR = "materialContainerTransition:containerColor"
64+
private val TRANSITION_PROPS = arrayOf(
65+
PROP_BOUNDS,
66+
PROP_BITMAP,
67+
PROP_SHAPE_APPEARANCE,
68+
PROP_CONTAINER_COLOR
69+
)
6270

6371
/**
6472
* A [Transition] which implements the Material Container pattern from
6573
* https://medium.com/google-design/motion-design-doesnt-have-to-be-hard-33089196e6c2
6674
*/
6775
class MaterialContainerTransition(
68-
@IdRes private val drawInId: Int = android.R.id.content
76+
@IdRes private val drawInId: Int = android.R.id.content,
77+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true)
78+
private val crossfadeStartProgress: Float = 0.3f,
79+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true)
80+
private val crossfadeEndProgress: Float = 0.8f
6981
) : Transition() {
7082

7183
override fun getTransitionProperties() = TRANSITION_PROPS
@@ -102,12 +114,15 @@ class MaterialContainerTransition(
102114
(startValues.values[PROP_SHAPE_APPEARANCE] as ShapeAppearanceModel?).toCornerRounding(
103115
startBounds
104116
),
117+
startValues.values[PROP_CONTAINER_COLOR] as Int,
118+
crossfadeStartProgress,
105119
endValues.values[PROP_BITMAP] as Bitmap,
106120
endBounds,
107121
(endValues.values[PROP_SHAPE_APPEARANCE] as ShapeAppearanceModel?).toCornerRounding(
108122
endBounds
109123
),
110-
view.descendantBackgroundColor()
124+
endValues.values[PROP_CONTAINER_COLOR] as Int,
125+
crossfadeEndProgress
111126
)
112127

113128
return ObjectAnimator.ofFloat(dr, PROGRESS, 0f, 1f).apply {
@@ -145,7 +160,7 @@ class MaterialContainerTransition(
145160
top + view.height
146161
)
147162
// Clear any foreground e.g. a ripple in progress
148-
view.foreground = null
163+
view.jumpDrawablesToCurrentState()
149164
// Add padding to the bitmap capture so that when we draw it later with a
150165
// [BitmapShader] with CLAMP [TileMode], the transparency is repeated.
151166
transitionValues.values[PROP_BITMAP] = view.drawToBitmap(BITMAP_PADDING_BOTTOM)
@@ -168,6 +183,7 @@ class MaterialContainerTransition(
168183
}
169184
}
170185
}
186+
transitionValues.values[PROP_CONTAINER_COLOR] = view.descendantBackgroundColor()
171187
}
172188
}
173189
}
@@ -178,14 +194,22 @@ class MaterialContainerTransition(
178194
*
179195
* Additionally it draws a scrim over non-shared elements and a background to the container.
180196
*/
197+
private const val scrimAlpha = 102 // 40% opacity
198+
private const val containerShadow = 0x1a000000
199+
private const val containerNoShadow = 0x00000000
181200
private class MaterialContainerTransitionDrawable(
182201
private val startImage: Bitmap,
183202
private val startBounds: RectF,
184203
private val startRadii: CornerRounding,
204+
@ColorInt private val containerStartColor: Int,
205+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true)
206+
private val crossfadeStartProgress: Float,
185207
private val endImage: Bitmap,
186208
private val endBounds: RectF,
187209
private val endRadii: CornerRounding,
188-
@ColorInt containerColor: Int = 0xffffffff.toInt(),
210+
@ColorInt private val containerEndColor: Int,
211+
@FloatRange(from = 0.0, fromInclusive = true, to = 1.0, toInclusive = true)
212+
private val crossfadeEndProgress: Float,
189213
@ColorInt scrimColor: Int = 0xff000000.toInt()
190214
) : Drawable() {
191215

@@ -198,7 +222,7 @@ private class MaterialContainerTransitionDrawable(
198222
}
199223
private val containerPaint = Paint().apply {
200224
style = Paint.Style.FILL
201-
color = containerColor
225+
color = containerStartColor
202226
}
203227
private val currentBounds = RectF(startBounds)
204228
private val entering = endBounds.height() > startBounds.height()
@@ -233,38 +257,56 @@ private class MaterialContainerTransitionDrawable(
233257
}
234258

235259
override fun draw(canvas: Canvas) {
236-
// Fade in/out 0–40% opaque scrim over non-shared elements
237-
// TODO make opacity configurable
260+
// Fade in/out a scrim over non-shared elements
238261
scrimPaint.alpha = if (entering) {
239-
lerp(0, 102, progress)
262+
lerp(0, scrimAlpha, progress)
240263
} else {
241-
lerp(102, 0, progress)
264+
lerp(scrimAlpha, 0, progress)
242265
}
243266
if (scrimPaint.alpha > 0) canvas.drawRect(bounds, scrimPaint)
244267

245-
// Animate corner radii changes over 0.3–0.8 of `progress` & use this when drawing the
268+
// Animate corner radii over the crossfade range & use this when drawing the
246269
// container background & images
247-
val cornerRadii = lerp(startRadii, endRadii, 0.3f, 0.8f, progress)
270+
val cornerRadii = lerp(
271+
startRadii,
272+
endRadii,
273+
crossfadeStartProgress,
274+
crossfadeEndProgress,
275+
progress
276+
)
248277

249278
// Draw a background for the container, useful when the container size exceeds the image
250279
// size which it can in large start/end size changes. Also fade in/out a shadow.
251-
// TODO make this configurable / density dependent
280+
// TODO make radius configurable / density dependent
252281
containerPaint.setShadowLayer(
253282
12f, 0f, 12f,
254283
if (entering) {
255-
lerpArgb(0, 0x1a000000, progress)
284+
lerpArgb(containerNoShadow, containerShadow, progress)
256285
} else {
257-
lerpArgb(0x1a000000, 0, progress)
286+
lerpArgb(containerShadow, containerNoShadow, progress)
258287
}
259288
)
289+
containerPaint.color = lerpArgb(
290+
containerStartColor,
291+
containerEndColor,
292+
crossfadeStartProgress,
293+
crossfadeEndProgress,
294+
progress
295+
)
260296
canvas.drawRoundedRect(
261297
currentBounds,
262298
cornerRadii,
263299
containerPaint
264300
)
265301

266-
// Cross-fade images of the start/end states over 0.3–0.8 of `progress`
267-
imagePaint.alpha = lerp(255, 0, 0.3f, 0.8f, progress)
302+
// Cross-fade images of the start/end states over the crossfade range
303+
imagePaint.alpha = lerp(
304+
255,
305+
0,
306+
crossfadeStartProgress,
307+
crossfadeEndProgress,
308+
progress
309+
)
268310
if (imagePaint.alpha > 0) {
269311
imagePaint.shader = startImageShader
270312
canvas.drawRoundedRect(
@@ -273,7 +315,13 @@ private class MaterialContainerTransitionDrawable(
273315
imagePaint
274316
)
275317
}
276-
imagePaint.alpha = lerp(0, 255, 0.3f, 0.8f, progress)
318+
imagePaint.alpha = lerp(
319+
0,
320+
255,
321+
crossfadeStartProgress,
322+
crossfadeEndProgress,
323+
progress
324+
)
277325
if (imagePaint.alpha > 0) {
278326
imagePaint.shader = endImageShader
279327
canvas.drawRoundedRect(

0 commit comments

Comments
 (0)