android glide加载不出图片_Glide实现共享元素无缝转场效果,只需四步!

431de7e7a0811bf5311bf1a74f5005c0.gif

原文: How to Use Shared Element Transition with Glide in 4 steps
作者:Bartłomiej Osmałek

读完这篇文章, 你就会知道使用Glide等图片加载库实现共享元素转场效果,以及如何处理各种可能加载状态。通过共享转场动画,可以提升应用交互体验,让用户使用起来更愉悦

95fe05d00468bc0e0adf898df782c349.png

共享元素转场效果是Material Design的一个重要的转场效果. 如果图片资源是静态本地的,那么实现起来是容易的。但是通过网络下载图片并且创建一个无缝的动画效果就比较棘手了。

开始之前

此篇文章是在开发Toast App时,对于转场效果的一个总结. 该app是TOAST – Android 开发者聚会(波兰最大的Android开发者聚会网站)的客户端app. app中包含了每个TOAST事件,定期讲座和活动照片。 我们主要用共享元素转场作为页面切换效果。同时使用Glide来获取所有的图片。

本文中介绍的方法也应适用于其他图像加载库,例如Picasso 或者 Fresco (您需要找到Glide特定功能的相对应的代码实现). 为此我制作了一个示例演示程序, 发布在Github上. 所有代码段均来自此示例程序。

我们使用一组网格图片作为开始. 当用户点击一张图片, 会打开一个新的Activity,图片会裁剪并填充整个屏幕。下面是使用Glide加载图片的相关代码:

fun ImageView.load(url: String) {
    Glide.with(this)
            .load(url)
            .apply(RequestOptions.placeholderOf(R.drawable.placeholder))
            .into(this)
}

我们想要的效果:

94d3280b5a787453de7119fe23caa418.gif

第一步: 幼稚的共享过渡

我们可以通过添加正确options来创建过渡效果,修改 goToDetails 方法如下:
MainActivity.kt

fun goToDetails(url: String, imageView: View) {
    val options = ActivityOptionsCompat.makeSceneTransitionAnimation(this, imageView, imageView.transitionName).toBundle()
    Intent(this, DetailActivity::class.java)
            .putExtra(IMAGE_URL_KEY, url)
            .let {
                startActivity(it, options)
            }
}

现在, 我们在上面的方法中传入要共享的view,并设置transitionName这个名称在每个activity中必须是唯一的,主视图和详情页面相对应的view的transitionName则要相同,在此为了简化,我们使用图片url作为transitionName:
DetailActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detail)
    val url = intent.getStringExtra(IMAGE_URL_KEY)
    detailImage.transitionName = url
    detailImage.load(url)
}

ImageAdapter.kt

inner class ImageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
    fun bind(url: String) {
        (itemView as ImageView).apply {
            load(url)
            transitionName = url
            setOnClickListener { onClick(url, it) }
        }
    }
}

好了, 我们有了过渡动画如下:

f72262314b478a99af8d9aad596099b6.gif

糟糕的是这并不是我们想要的效果?

第二步: 推迟过渡效果

Glide需要时间将图片加载到ImageView. 这就是为什么在onCreate中 我们不得不推迟过过渡动画效果,直到图片下载完成才可以开始进行过渡效果: DetailActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    supportPostponeEnterTransition()
    detailImage.load(url) {
        supportStartPostponedEnterTransition()
    }
}

GlideLoader.kt

fun ImageView.load(url: String, onLoadingFinished: () -> Unit = {}) {
    val listener = object : RequestListener {override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
            onLoadingFinished()return false
        }override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
            onLoadingFinished()return false
        }
    }
    Glide.with(this)
            .load(url)
            .apply(RequestOptions.placeholderOf(R.drawable.placeholder))
            .listener(listener)
            .into(this)
}
5cc6c2cfcc7b68167fbd75915aad393b.gif

现在我们在过渡前图片已经加载了,但可以看到的是在进入过渡之前以及退出过渡之后会有奇怪的毛刺,我们将在下一步处理它。

第三步: 禁止转换

之所以有这个毛刺效果是由于Glide在加载时进行的优化。默认的, Glide为了匹配目标view会调整图片大小并裁剪图片。但是Android过渡框架在过渡开始时会从目标视图获取图像,并且将它转换到源视图的图像。我们可以让Glide不进行这些优化:
GlideLoader.kt

fun ImageView.load(url: String, onLoadingFinished: () -> Unit = {}) {
    ...
    val requestOptions = RequestOptions.placeholderOf(R.drawable.placeholder)
            .dontTransform()
    Glide.with(this)
            .load(url)
            .apply(requestOptions)
            .listener(listener)
            .into(this)
}

我们也可以在Glide中使用原始图片大小。 这会减少过渡延迟,因为原始图片会存在于内存中,不会在磁盘缓存中。注意:此操作会让你的的程序变慢,需要小心使用。如果你一定要这样做的花,这里有个修改的分支可以参考下.

250d608a73b9090e69a94124d4d3ac90.gif

现在可以正常使用了,但在一些错误链接图片获取未加载完成但图片就会有一个小问题。

f1fed308167dfa2eb99a09b51588a364.gif

第四步: 仅在Cache时传输

我们要在任何条件下都可以无缝过渡,最简单的方式是从缓存中获取图片 (或者如果图片未加载完成时, 就使用占位图)。DetailActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    detailImage.load(url, loadOnlyFromCache = true) {
        supportStartPostponedEnterTransition()
    }
}

GlideLoader.kt

fun ImageView.load(url: String, loadOnlyFromCache: Boolean = false, onLoadingFinished: () -> Unit = {}) {
    ...
    val requestOptions = RequestOptions.placeholderOf(R.drawable.placeholder)
            .dontTransform()
            .onlyRetrieveFromCache(loadOnlyFromCache)
    ...
}
781f1ff8e71064b43e94564e1ac2d81b.gif

当然,这意味着用户打开详情页面时,在图片加载完成之前,只会显示占位图。它会在过渡结束后通过第二次请求来修复:
DetailActivity.kt

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    window.sharedElementEnterTransition = TransitionSet()
            .addTransition(ChangeImageTransform())
            .addTransition(ChangeBounds())
            .apply {
                doOnEnd { detailImage.load(url) }
            }

90cef4f1acaebc458a45e31d74e054e1.gif

最终,我们有了一个非常棒的过渡转场效果,它可以工作在各种条件下。您可以在GitHub上查看整个示例,也可以在Toast App中查看更多示例。

总结

共享元素过渡提供了视觉上的连续性,并保持了用户的注意力。但是我们应该记住,我们的互联网连接可能很差,冻结的过渡可能会激怒用户。我相信这4个步骤将在任何情况下帮助您使您的应用程序美观且快速。

相关链接

  • Workcation App – Part 4. Shared Element Transition with RecyclerView and Scenes

  • Meaningful Motion with Shared Element Transition and Circular Reveal Animation

  • Workcation App – Part 1. Fragment custom transition

  • How to Learn Android Development Programming – 6 Steps for Beginners

  • 6 Misconceptions about TDD – Part 4. There is one right granularity of steps

---END---

推荐阅读:
谈谈Android AOP技术方案
2020年,Github就该这么玩!
有个程序员老公有多爽???
最新7月份编程语言排行榜,C语言仍霸榜单!R语言史无前例的高光时刻
Fragment 的新特性:“Fragment 间传递数据的新方式” ,以及源码分析!
热门Android Studio 插件,这里是Top 20!
ViewHolder的MVVM实现
面试官问:说说消息队列常用的几种场景?

006af761f715ac8912f8bf19d36349f5.png

更文不易,点个“在看”支持一下?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值