Mr.Bendan
Mr.Bendan

Reputation: 3

How to animate an image property

I want to load image with saturation animation. Here is code useful by Glide,ImageView and ValueAnimator.

Glide.with(imageView)
            .asBitmap()
            .load(url)
            .transition(BitmapTransitionOptions.withCrossFade(1000))
            .apply(RequestOptions.placeholderOf(new ColorDrawable(Color.LTGRAY)))
            .listener(new RequestListener<Bitmap>() {

                @Override
                public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Bitmap> target, boolean isFirstResource) {
                    return false;
                }

                @Override
                public boolean onResourceReady(Bitmap resource, Object model, Target<Bitmap> target, DataSource dataSource, boolean isFirstResource) {
                    ValueAnimator animation = ValueAnimator.ofFloat(0F, 1F);
                    animation.setDuration(3000);
                    animation.setInterpolator(new LinearInterpolator());
                    animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                        @Override
                        public void onAnimationUpdate(ValueAnimator it) {
                            ColorMatrix mt = new ColorMatrix();
                            mt.setSaturation(it.getAnimatedFraction());

                            ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(mt);
                            imageView.setColorFilter(colorFilter);
                        }
                    });
                    animation.start();
                    return false;
                }

            })
            .into(imageView);

It's useful, but I want to implement with Jetpack Compose and coil, I have wrong. Here this my code.

var imgConfig by remember { mutableStateOf(ColorMatrix()) }

val animation = ValueAnimator.ofFloat(0F, 1F)
animation.duration = 3000
animation.addUpdateListener {
    Log.d("ValueAnimator", "new value ${it.animatedFraction}")
    imgConfig = ColorMatrix().apply {
        setToSaturation(it.animatedFraction)
    }
}
val request = ImageRequest.Builder(LocalContext.current)
    .data(url)
    .apply { this.placeholder(ColorDrawable(android.graphics.Color.LTGRAY)).crossfade(true) }
    .listener(onStart = {
        Log.d("AnimationImgLoader", "onStar");
    }, onCancel = {
        Log.d("AnimationImgLoader", "onCancel");
    }, onError = { request: ImageRequest, throwable: Throwable ->
        Log.e("AnimationImgLoader", "onError ${throwable.message}")
    }, onSuccess = { request: ImageRequest, metadata: ImageResult.Metadata ->
        Log.d("AnimationImgLoader", "onSuccess ")
        animation.start()
    })
    .build()
Image(
    painter = rememberImagePainter(request = request),
    contentDescription = "RemoteImage",
    colorFilter = ColorFilter.colorMatrix(imgConfig)
)

Use this code, in my Android Studio Logcat I found too many log is AnimationImgLoader: onStar.

I want to know, why it is? And how to fix it.

Upvotes: 0

Views: 675

Answers (1)

Johann
Johann

Reputation: 29877

You probably should avoid using the older animation system with the newer animation system designed for Compose. Here is how you animate a floating value in Compose and apply it to a property such as the image saturation:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        startActivity(intent)

        setContent {
            AnimatedImage(url = "https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Cat03.jpg/1200px-Cat03.jpg")
        }
    }
}


@Composable
fun AnimatedImage(
    url: String
) {
    var enabled by remember { mutableStateOf(false)}
    val saturation by animateFloatAsState(targetValue = if (enabled) 1f else 0f, animationSpec = tween(3000))

    val colorMatrix = ColorMatrix()
    colorMatrix.setToSaturation(saturation)

    val request = ImageRequest.Builder(LocalContext.current)
        .data(url)
        .apply { this.placeholder(ColorDrawable(Color.LTGRAY)).crossfade(true) }
        .listener(onStart = {
            Log.d("AnimationImgLoader", "onStar");
        }, onCancel = {
            Log.d("AnimationImgLoader", "onCancel");
        }, onError = { request: ImageRequest, throwable: Throwable ->
            Log.e("AnimationImgLoader", "onError ${throwable.message}")
        }, onSuccess = { request: ImageRequest, metadata: ImageResult.Metadata ->
            Log.d("AnimationImgLoader", "onSuccess ")
            //animation.start()
            enabled = true
        })
        .build()
    Image(
        painter = rememberImagePainter(request = request),
        contentDescription = "RemoteImage",
        colorFilter = ColorFilter.colorMatrix(colorMatrix)
    )
}

Upvotes: 1

Related Questions