Reputation: 5055
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);
Upvotes: 117
Views: 85767
Reputation: 723
// 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);
Upvotes: 1
Reputation: 41
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)
}
Upvotes: 4
Reputation: 13218
@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.
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) {
}
});
Upvotes: 0
Reputation: 11
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.
use noFade()
set image_view's scaleType to "CENTER_INSIDE"
Upvotes: 1
Reputation: 535
Just use Picasso PlaceHolder
Picasso.get()
.load(datas[position].artist?.image)
.placeholder(R.drawable.music_image)
.error(R.drawable.music_image)
.into(holder.cardViewImage)
Upvotes: 0
Reputation: 1038
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);
Upvotes: 1
Reputation: 3661
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
/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 );
Upvotes: 271
Reputation: 13555
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
Upvotes: 0
Reputation: 23
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'
Upvotes: 0
Reputation: 1304
I made it working in following way:
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>
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"/>
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);
}
};
Results will be like that on loading - circle is rotating (sorry for this screenshot, but images are appearing too fast): ScreenShot
Upvotes: 0
Reputation: 3623
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. :)
Upvotes: 77
Reputation: 1204
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
Upvotes: 5