Picasso中的动画加载图片

116

我有以下代码用于在Picasso中加载图像,使用drawable作为占位符在下载图像时显示。但是我想要的是一个旋转的进度条样式的spinner,在图像加载时循环播放动画,就像我在大多数专业应用程序中看到的那样。Picasso似乎不支持这一点,只支持静态图像drawable。是否有办法在Picasso中实现此功能,或者我必须采取不同的方法?

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

270

如何使用Picasso占位符实现加载进度动画图像:

我轻松地使用了一个animated-rotate的xml对象来解决这个问题。

步骤:

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.with( context )
        .load( your_path )
        .error( R.drawable.ic_error )
        .placeholder( R.drawable.progress_animation )
        .into( image_view );

33
@DBragion它的表现很好,但对于大型图像,它被放大了。我们能否将其宽度和高度固定为像32x32像素这样的数字? - m3hdi
10
不起作用,没有动画显示,只有一张简单的图片。 - Joe Maher
4
它可以工作,但我想要一个小的加载器,而不是与我的ImageView大小相同的加载器。 - Ganpat Kaliya
2
工作得很好,动画在下载的图像出现前几毫秒保持小型,然后在几毫秒内最大化和拉伸,然后图像出现。有什么解决方案吗? - tinyCoder
2
使用http://romannurik.github.io/AndroidAssetStudio/index.html(选择“启动器图标生成器”)创建mdpi,hdpi,xhdpi等。 - CoolMind
显示剩余15条评论

77

我已经实现了进度对话框到图像下载,而且非常简单。在相对布局中取出你的ImageView,然后将进度加载器放置在同一个ImageView上。应用以下代码并仅处理进度对话框的可见性。

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

                }
            });
        }

享受吧。:)


谢谢,这对我很有帮助 :) - Zohair
2
太棒了!目前为止最佳解决方案,可以在许多不同的情境中使用。 :) - VVZen
7
你应该注意弱引用并以这种方式声明一个“回调对象”以避免垃圾回收(否则onSuccess永远不会被调用):final Callback loadedCallback = new Callback() { @Override public void onSuccess() { // 你的代码 } @Override public void onError() { // 你的代码 } }; imageView.setTag(loadedCallback); Picasso.with(context).load(url).into(imageView, loadedCallback); - VVZen
任何对术语感到困惑的人,进度加载器是一个进度条。 - Joe Maher
2
你忘记添加RoundedTransformation类了。这个类在这里 https://gist.github.com/aprock/6213395 - Md. Sajedul Karim
对于多个图像而言,这并没有什么帮助。这只会使用户界面变得复杂无比,毫无意义。 - Tushar Gogna

5

很遗憾,Picasso不支持动画占位符。

你可以通过将ImageView放置在带有动画drawable的FrameLayout中来解决这个问题。这样当Picasso加载图像时,它将在动画占位符上方加载图像,给用户带来预期效果。

或者,你可以将图像加载到Target中。这样默认情况下进度条会显示,当调用onBitmapLoaded方法时,你可以隐藏它并显示图像。你可以在此处看到一个基本实现。


3
Picasso支持动画占位符。您需要编写一个动画drawable文件(包括表示动画中每个图像的几个项的动画列表)。然后,将该文件传递给新的AnimationDrawable对象,然后将其传递到Picasso加载器构造函数中的placeHolder()方法中。 - Odaym

4
我在stackoverflow上尝试了很多方法,最终发现使用“CircularProgressDrawable”是一种可行的方法。参考链接:https://developer.android.com/reference/androidx/swiperefreshlayout/widget/CircularProgressDrawable Kotlin代码示例:
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)
}

1
   // 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);

1
只需像下面这样在DBragion的答案中添加形状属性,它就会像魔法一样运行。 愉快的编程。
<?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>

你也可以使用Glide:

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

1
我找到了这个问题的答案!
请看:https://github.com/square/picasso/issues/427#issuecomment-266276253 除了 @DBragion 的回答,还可以尝试以下方法。
现在我们可以修复高度和宽度!
image_view.scaleType = ImageView.ScaleType.CENTER_INSIDE

picasso.load(your_path)
        .fit()
        .centerCrop()
        .noFade()
        .placeholder(R.drawable. progress_animation)
        .into(image_view)

我认为有两个关键点。
  1. 使用 noFade() 方法

  2. 将 image_view 的 scaleType 设置为 "CENTER_INSIDE"


0

我是这样让它工作的:

  1. 创建了一个可绘制对象(从互联网上找到的),并将其放置在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. 在GridView的项目中添加了ProgressBar元素:

    <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. 在适配器中添加了Target对象,具有以下参数,其中poster和spinner是ImageView和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. 加载时的结果如下 - 圆圈正在旋转(对于这个截图很抱歉,但是图片出现得太快了): ScreenShot


0
在这个链接中,Jake Wharton说:

不行。我们使用Android BitmapFactory进行所有图像解码,但它没有动态GIF支持(可悲)。

那么你就不能做到。


0

只需使用Picasso占位符

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接