Animated loading image in picasso

AndroidPicasso

Android Problem Overview


I have the following code to load an image in Picasso, using a drawable for the placeholder to display while the image is downloading. What I want though is an animated spinning progress bar style spinner that animates around and around while the image is loading, like I see in most professional apps. Picasso doesn't seem to support this, only static image drawables. Is there a way to get it working with Picasso or do I have to do something different?

Picasso.with(context).load(url)	        	
		        	.placeholder(R.drawable.loading)
		        	.error(R.drawable.image_download_error)
		        	.into(view);

Android Solutions


Solution 1 - Android

How to have a loading progress animation image using Picasso placeholder:

I solved this easily using a animated-rotate xml object.

Steps:

progress_image.png

progress_image.png

/res/drawable/progress_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

<item android:gravity="center">
    <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/progress_image"
        android:pivotX="50%"
        android:pivotY="50%" />
    </item>
</layer-list>

Picasso loading:

Picasso.with( context )
		.load( your_path )
		.error( R.drawable.ic_error )
		.placeholder( R.drawable.progress_animation )
		.into( image_view );

Solution 2 - Android

I implemented the progress dialog till the image download and its very simple. Take your ImageView in relative layout and place progress loader on same image view. Apply the below code and handle progress dialog visibility only.

holder.loader.setVisibility(View.VISIBLE);
            holder.imageView.setVisibility(View.VISIBLE);
         final ProgressBar progressView = holder.loader;
            Picasso.with(context)
            .load(image_url)
            .transform(new RoundedTransformation(15, 0))
            .fit()
            .into(holder.imageView, new Callback() {
                @Override
                public void onSuccess() {
                    progressView.setVisibility(View.GONE);
                }

                @Override
                public void onError() {
                    // TODO Auto-generated method stub

                }
            });
        }

Enjoy. :)

Solution 3 - Android

Picasso doesn't support animated placeholders unfortunately.

One way you could work around this is to place your ImageView in a FrameLayout with the animated drawable underneath. This way when Picasso loads the image it will load over the top of the animated placeholder, giving the user the intended effect.

Alternatively, you could load the image into a Target. Then you'd have the progress bar showing by default, and when the onBitmapLoaded method is called you can hide it and display the image. You can see a basic implementation of this here

Solution 4 - Android

I've tried many ways on the stack overflow and finally found a way to do it is using "CircularProgressDrawable". Ref: https://developer.android.com/reference/androidx/swiperefreshlayout/widget/CircularProgressDrawable

Kotlin code sample

fun Context.loadImage(view: ImageView, url: String) {
  val circularProgressDrawable = CircularProgressDrawable(this)
  circularProgressDrawable.apply {
    strokeWidth = 5f
    centerRadius = 30f
    setColorSchemeColors(
      getColor(Color.WHITE)
    )
    start()
  }

  Picasso
    .get()
    .load(url)
    .fit()
    .centerInside()
    .placeholder(circularProgressDrawable)
    .into(view)
}

Solution 5 - Android

Just add shape attribute in DBragion's answer as like below and it will work like charm. Happy coding.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>

        <shape
            android:shape="rectangle">

            <size
                android:width="200dp"
                android:height="200dp"/>

            <solid
                android:color="#00FFFFFF"/>
        </shape>
    </item>

    <item android:gravity="center">
        <animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
            android:drawable="@drawable/spinner"
            android:pivotX="50%"
            android:pivotY="50%" />
    </item>
</layer-list>

You can use Glide too:

Glide.with(activity).load(url)
                    .apply(RequestOptions.centerInsideTransform())
                    .placeholder(R.drawable.progress_animation)
                    .into(imageview);

Solution 6 - Android

I found answer to this question!

See: https://github.com/square/picasso/issues/427#issuecomment-266276253

In addition to answer of @DBragion, try below.

Now we can fix height and width!

image_view.scaleType = ImageView.ScaleType.CENTER_INSIDE
picasso.load(your_path)
        .fit()
        .centerCrop()
        .noFade()
        .placeholder(R.drawable. progress_animation)
        .into(image_view)

I think there are two key points.

  1. use noFade()

  2. set image_view's scaleType to "CENTER_INSIDE"

Solution 7 - Android

I made it working in following way:

  1. Created a drawable (found somewhere on the Internet) and put it in the res/drawable:

     <?xml version="1.0" encoding="utf-8"?>
     <rotate xmlns:android="http://schemas.android.com/apk/res/android"
     android:fromDegrees="90"
     android:pivotX="50%"
     android:pivotY="50%"
     android:toDegrees="360">
    
     <shape
         android:innerRadiusRatio="3"
         android:shape="ring"
         android:thicknessRatio="7.0">
    
         <gradient
             android:angle="0"
             android:centerColor="#007DD6"
             android:endColor="#007DD6"
             android:startColor="#007DD6"
             android:type="sweep"
             android:useLevel="false" />
     </shape>
    

  2. In my item for the GridView added ProgressBar element:

     <ProgressBar
         android:id="@+id/movie_item_spinner"
         android:layout_width="@dimen/poster_width"
         android:layout_height="@dimen/poster_height"
         android:progressDrawable="@drawable/circular_progress_bar"/>
    
  3. In Adapter added Target Object with following parameters, where poster and spinner are references to ImageView and ProgressBar:

    // Target to show/hide ProgressBar on ImageView

     final Target target = new Target() {
    
             @Override
             public void onPrepareLoad(Drawable drawable) {
                 poster.setBackgroundResource(R.color.white);
                 spinner.setVisibility(View.VISIBLE);
             }
    
             @Override
             public void onBitmapLoaded(Bitmap photo, Picasso.LoadedFrom from) {
                 poster.setBackgroundDrawable(new BitmapDrawable(photo));
                 spinner.setVisibility(View.GONE);
             }
    
             @Override
             public void onBitmapFailed(Drawable drawable) {
                 poster.setBackgroundResource(R.color.white);
             }
         };
    
  4. Results will be like that on loading - circle is rotating (sorry for this screenshot, but images are appearing too fast): ScreenShot

Solution 8 - Android

For anyone trying to use DBragion's technique: Make sure you have the latest version of Picasso or else it wont spin. Mine didn't work until I used version 2.5.2.

compile 'com.squareup.picasso:picasso:2.5.2'

Solution 9 - Android

In this link, Jake Wharton said :

> Nope. We use the Android BitmapFactory for all image decoding and it has no animated GIF support (sadly).

Then you can't

Solution 10 - Android

Just use Picasso PlaceHolder

  Picasso.get()
        .load(datas[position].artist?.image)
        .placeholder(R.drawable.music_image)
        .error(R.drawable.music_image)
        .into(holder.cardViewImage)

Solution 11 - Android

@DBragion's answer was great. The problem with it (like many mentioned in the comments) was it didn't provide a way to specify the height / width of the progress indicator. Following is the modified version of his answer with combination of @AkankshaRathod's answer.

loading_indicator.png

Loading Indicator Image

progress_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:gravity="center">
        <animated-rotate
            android:drawable="@drawable/loading_indicator"
            android:pivotX="50%"
            android:pivotY="50%" />
    </item>
</layer-list>

CardView (or any container Layout) containing your ImageView

<androidx.cardview.widget.CardView
    android:id="@+id/vCategoryItem"
    android:layout_width="wrap_content"
    android:layout_height="@dimen/height_category_image"
    android:layout_marginLeft="@dimen/smaller"
    app:cardCornerRadius="@dimen/small">

    <ImageView
        android:id="@+id/imgCategoryImage"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:adjustViewBounds="true"
        android:scaleType="centerCrop"
        android:src="@drawable/demo" />

    <ImageView
        android:id="@+id/loadingIndicator"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_gravity="center"
        android:layout_centerInParent="true"
        android:src="@drawable/progress_animation" />

    <TextView
        android:id="@+id/lblCategoryName"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_gravity="bottom"
        android:layout_marginBottom="@dimen/big"
        android:ellipsize="marquee"
        android:gravity="center"
        android:paddingLeft="@dimen/big"
        android:paddingRight="@dimen/big"
        android:singleLine="true"
        android:text="Category Name"
        android:textColor="@android:color/white"
        android:textSize="15sp"
        android:textStyle="bold" />

</androidx.cardview.widget.CardView>

Picasso loading:

Picasso.get().load(yourImageURL).into(imgCategoryImage, new Callback() {
    @Override
    public void onSuccess() {
        loadingIndicator.setVisibility(View.GONE);
    }

    @Override
    public void onError(Exception e) {

    }
});

Solution 12 - Android

   // create a ProgressDrawable object which we will show as placeholder
    CircularProgressDrawable progress = new CircularProgressDrawable(context);
    progress.setColorSchemeColors(R.color.colorPrimary, R.color.colorPrimaryDark, R.color.colorAccent);
    progress.setCenterRadius(30f);
    progress.setStrokeWidth(5f);
    progress.start();

Picasso.with(context).load((String) chatMessage.getPath()).error(R.drawable.error)
                    .placeholder(progress)
                    .noFade()
                    .into(viewHolder.imageBody);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionNZJamesView Question on Stackoverflow
Solution 1 - AndroidDBragionView Answer on Stackoverflow
Solution 2 - AndroidAkanksha RathoreView Answer on Stackoverflow
Solution 3 - AndroidMichaelView Answer on Stackoverflow
Solution 4 - AndroidukhomeView Answer on Stackoverflow
Solution 5 - AndroidTushar LathiyaView Answer on Stackoverflow
Solution 6 - AndroidYusuke YoneharaView Answer on Stackoverflow
Solution 7 - AndroidDmytro KarataievView Answer on Stackoverflow
Solution 8 - AndroidJesse AbruzzoView Answer on Stackoverflow
Solution 9 - AndroidRadeshView Answer on Stackoverflow
Solution 10 - AndroidExel StaderlinView Answer on Stackoverflow
Solution 11 - AndroidMahendra LiyaView Answer on Stackoverflow
Solution 12 - AndroidYasin EgeView Answer on Stackoverflow