Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Always fade in from placeholder with Picasso

I still don't know if this is a bug report or a feature request, so bear with me.

I'm using Picasso and I've noticed that the sample application always fades in from the previous image (see here for a demo of what I mean). However, I would like it to always fade in from a given placeholder.

My guess for this behaviour is that the views of the grid are recycled and Picasso does not set the placeholder before fading in to the actual image.

Is this on purpose? How would I be able to always fade in from a placeholder?

like image 410
Sebastiano Avatar asked Feb 28 '14 14:02

Sebastiano


1 Answers

Picasso suport some fade animation in specific case. However, it was not working for me because I'me using a custom Target with picasso which allow me to set background drawable.

I've copied PicassocDrawable which have a nice fade animation and add public constructor.

/* Copyright (C) 2013 Square, 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 com.example.app;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.AnimationDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.SystemClock;
import android.widget.ImageView;

/**
 * Changelog :
 * - Modified from Picasso 2.5.0 to allow public instantiation
 */
public class CustomPicassoDrawable extends BitmapDrawable{
    // Only accessed from main thread.
    private static final Paint DEBUG_PAINT = new Paint();
    private static final float FADE_DURATION = 200f; //ms

    /**
     * Create or update the drawable on the target {@link android.widget.ImageView} to display the supplied bitmap
     * image.
     */
    static void setBitmap(ImageView target, Context context, Bitmap bitmap) {
        Drawable placeholder = target.getDrawable();
        if (placeholder instanceof AnimationDrawable) {
            ((AnimationDrawable) placeholder).stop();
        }
        CustomPicassoDrawable drawable =
                new CustomPicassoDrawable(context, bitmap, placeholder);
        target.setImageDrawable(drawable);
    }

    /**
     * Create or update the drawable on the target {@link ImageView} to display the supplied
     * placeholder image.
     */
    static void setPlaceholder(ImageView target, Drawable placeholderDrawable) {
        target.setImageDrawable(placeholderDrawable);
        if (target.getDrawable() instanceof AnimationDrawable) {
            ((AnimationDrawable) target.getDrawable()).start();
        }
    }

    private final float density;

    Drawable placeholder;

    long startTimeMillis;
    boolean animating;
    int alpha = 0xFF;

    public CustomPicassoDrawable(Context context, Bitmap bitmap, Drawable placeholder) {
        super(context.getResources(), bitmap);

        this.density = context.getResources().getDisplayMetrics().density;

        this.placeholder = placeholder;
        animating = true;
        startTimeMillis = SystemClock.uptimeMillis();
    }

    @Override public void draw(Canvas canvas) {
        if (!animating) {
            super.draw(canvas);
        } else {
            float normalized = (SystemClock.uptimeMillis() - startTimeMillis) / FADE_DURATION;
            if (normalized >= 1f) {
                animating = false;
                placeholder = null;
                super.draw(canvas);
            } else {
                if (placeholder != null) {
                    placeholder.draw(canvas);
                }

                int partialAlpha = (int) (alpha * normalized);
                super.setAlpha(partialAlpha);
                super.draw(canvas);
                super.setAlpha(alpha);
                if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
                    invalidateSelf();
                }
            }
        }
    }

    @Override public void setAlpha(int alpha) {
        this.alpha = alpha;
        if (placeholder != null) {
            placeholder.setAlpha(alpha);
        }
        super.setAlpha(alpha);
    }

    @Override public void setColorFilter(ColorFilter cf) {
        if (placeholder != null) {
            placeholder.setColorFilter(cf);
        }
        super.setColorFilter(cf);
    }

    @Override protected void onBoundsChange(Rect bounds) {
        if (placeholder != null) {
            placeholder.setBounds(bounds);
        }
        super.onBoundsChange(bounds);
    }
}

You can use it with

Picasso
.with(this)
.load("http://yourimage")
.into(new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
        CustomPicassoDrawable drawable = new CustomPicassoDrawable(
                FullscreenActivity.this, bitmap, myBackground);
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
            myView.setBackground(drawable);
        } else {
            myView.setBackgroundDrawable(drawable);
        }
    }

    @Override
    public void onBitmapFailed(Drawable errorDrawable) {}

    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {}
});
like image 133
Hugo Gresse Avatar answered Oct 28 '22 04:10

Hugo Gresse