Skip to content

Commit

Permalink
Fix drawables not animating via a custom DrawablePainter
Browse files Browse the repository at this point in the history
  • Loading branch information
sjudd committed Sep 3, 2023
1 parent 374306f commit 59c2d9b
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 3 deletions.
1 change: 0 additions & 1 deletion integration/compose/build.gradle
Expand Up @@ -53,7 +53,6 @@ dependencies {
}
implementation libs.compose.foundation
implementation libs.compose.ui
implementation libs.drawablepainter
implementation libs.androidx.core.ktx
debugImplementation libs.compose.ui.testmanifest
androidTestImplementation libs.junit
Expand Down
@@ -1,7 +1,10 @@
package com.bumptech.glide.integration.compose

import android.graphics.PointF
import android.graphics.drawable.Animatable
import android.graphics.drawable.Drawable
import android.os.Handler
import android.os.Looper
import androidx.compose.ui.Alignment
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
Expand Down Expand Up @@ -146,6 +149,10 @@ internal data class GlideNodeElement constructor(
}
}

private val MAIN_HANDLER by lazy(LazyThreadSafetyMode.NONE) {
Handler(Looper.getMainLooper())
}

@ExperimentalGlideComposeApi
@OptIn(InternalGlideApi::class)
internal class GlideNode : DrawModifierNode, LayoutModifierNode, SemanticsModifierNode,
Expand Down Expand Up @@ -178,6 +185,23 @@ internal class GlideNode : DrawModifierNode, LayoutModifierNode, SemanticsModifi

private var transition: Transition = DoNotTransition


private val callback: Drawable.Callback by lazy {
object : Drawable.Callback {
override fun invalidateDrawable(d: Drawable) {
invalidateDraw()
}

override fun scheduleDrawable(d: Drawable, what: Runnable, time: Long) {
MAIN_HANDLER.postAtTime(what, time)
}

override fun unscheduleDrawable(d: Drawable, what: Runnable) {
MAIN_HANDLER.removeCallbacks(what)
}
}
}

private fun RequestBuilder<*>.maybeImmediateSize() =
this.overrideSize()?.let { ImmediateGlideSize(it) }

Expand Down Expand Up @@ -398,7 +422,15 @@ internal class GlideNode : DrawModifierNode, LayoutModifierNode, SemanticsModifi

private fun updateDrawable(drawable: Drawable?) {
this.drawable = drawable

this.drawable?.callback = null
this.drawable?.setVisible(false, false)
(this.drawable as? Animatable)?.stop()

painter = drawable?.toPainter()
drawable?.callback = callback
drawable?.setVisible(true, true)
(drawable as? Animatable)?.start()
drawablePositionAndSize = null
}

Expand Down
Expand Up @@ -3,12 +3,24 @@ package com.bumptech.glide.integration.compose
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.asAndroidColorFilter
import androidx.compose.ui.graphics.asImageBitmap
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.nativeCanvas
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.ColorPainter
import androidx.compose.ui.graphics.painter.Painter
import com.google.accompanist.drawablepainter.DrawablePainter
import androidx.compose.ui.graphics.withSave
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.toSize
import kotlin.math.roundToInt

internal fun Drawable?.toPainter(): Painter =
when (this) {
Expand All @@ -17,3 +29,59 @@ internal fun Drawable?.toPainter(): Painter =
null -> ColorPainter(Color.Transparent)
else -> DrawablePainter(mutate())
}

private class DrawablePainter(
val drawable: Drawable
) : Painter() {
init {
if (drawable.isIntrinsicSizeValid) {
drawable.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight)
}
}

private var drawableIntrinsicSize = drawable.intrinsicSize

private val Drawable.isIntrinsicSizeValid
get() = intrinsicWidth >= 0 && intrinsicHeight >= 0

private val Drawable.intrinsicSize: Size
get() = if (isIntrinsicSizeValid) {
IntSize(intrinsicWidth, intrinsicHeight).toSize()
} else {
Size.Unspecified
}

override fun applyAlpha(alpha: Float): Boolean {
drawable.alpha = (alpha * 255).roundToInt().coerceIn(0, 255)
return true
}

override fun applyColorFilter(colorFilter: ColorFilter?): Boolean {
drawable.colorFilter = colorFilter?.asAndroidColorFilter()
return true
}

override fun applyLayoutDirection(layoutDirection: LayoutDirection): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
return drawable.setLayoutDirection(
when (layoutDirection) {
LayoutDirection.Ltr -> View.LAYOUT_DIRECTION_LTR
LayoutDirection.Rtl -> View.LAYOUT_DIRECTION_RTL
}
)
}
return false
}

override val intrinsicSize: Size get() = drawableIntrinsicSize

override fun DrawScope.onDraw() {
drawIntoCanvas { canvas ->
drawable.setBounds(0, 0, size.width.roundToInt(), size.height.roundToInt())

canvas.withSave {
drawable.draw(canvas.nativeCanvas)
}
}
}
}
1 change: 0 additions & 1 deletion settings.gradle
Expand Up @@ -115,7 +115,6 @@ dependencyResolutionManagement {
library('dagger-android.support', 'com.google.dagger', 'dagger-android-support').versionRef('dagger')
library('dagger-android.processor', 'com.google.dagger', 'dagger-android-processor').versionRef('dagger')
library('dokka-gradle', 'org.jetbrains.dokka:dokka-gradle-plugin:1.7.10')
library('drawablepainter', 'com.google.accompanist:accompanist-drawablepainter:0.25.1')
library('errorprone-annotations', 'com.google.errorprone', 'error_prone_annotations').versionRef('errorprone')
library('errorprone-core', 'com.google.errorprone', 'error_prone_core').versionRef('errorprone')
library('errorprone-gradle', 'net.ltgt.gradle:gradle-errorprone-plugin:2.0.2')
Expand Down

0 comments on commit 59c2d9b

Please sign in to comment.