原文: How to Use Shared Element Transition with Glide in 4 steps
做者:Bartłomiej Osmałek
Markdown:原文 | 譯文java
讀完這篇文章, 你就會知道使用Glide等圖片加載庫實現共享元素轉場效果,以及如何處理各類可能加載狀態。經過共享轉場動畫,能夠提高應用交互體驗,讓用戶使用起來更愉悅android
共享元素轉場效果是Material Design的一個重要的轉場效果. 若是圖片資源是靜態本地的,那麼實現起來是容易的。可是經過網絡下載圖片而且建立一個無縫的動畫效果就比較棘手了。git
此篇文章是在開發Toast App時,對於轉場效果的一個總結. 該app是TOAST – Android 開發者聚會(波蘭最大的Android開發者聚會網站)的客戶端app. app中包含了每一個TOAST事件,按期講座和活動照片。 咱們主要用共享元素轉場做爲頁面切換效果。同時使用Glide來獲取全部的圖片。github
本文中介紹的方法也應適用於其餘圖像加載庫,例如Picasso 或者 Fresco (您須要找到Glide特定功能的相對應的代碼實現). 爲此我製做了一個示例演示程序, 發佈在http://www.javashuo.com/tag/github上. 全部代碼段均來自此示例程序。緩存
咱們使用一組網格圖片做爲開始. 當用戶點擊一張圖片, 會打開一個新的Activity,圖片會裁剪並填充整個屏幕。下面是使用Glide加載圖片的相關代碼:網絡
fun ImageView.load(url: String) {
Glide.with(this)
.load(url)
.apply(RequestOptions.placeholderOf(R.drawable.placeholder))
.into(this)
}
複製代碼
咱們能夠經過添加正確options
來建立過渡效果,修改 goToDetails
方法以下:
MainActivity.ktapp
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)
}
複製代碼
inner class ImageViewHolder(view: View) : RecyclerView.ViewHolder(view) {
fun bind(url: String) {
(itemView as ImageView).apply {
load(url)
transitionName = url
setOnClickListener { onClick(url, it) }
}
}
}
複製代碼
好了, 咱們有了過渡動畫以下:優化
糟糕的是這並非咱們想要的效果🙁
Glide須要時間將圖片加載到ImageView. 這就是爲何在onCreate
中 咱們不得不推遲過過渡動畫效果,直到圖片下載完成才能夠開始進行過渡效果: DetailActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
...
supportPostponeEnterTransition()
detailImage.load(url) {
supportStartPostponedEnterTransition()
}
}
複製代碼
fun ImageView.load(url: String, onLoadingFinished: () -> Unit = {}) {
val listener = object : RequestListener<Drawable> {
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)
}
複製代碼
如今咱們在過渡前圖片已經加載了,但能夠看到的是在進入過渡以前以及退出過渡以後會有奇怪的毛刺,咱們將在下一步處理它。
之因此有這個毛刺效果是因爲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中使用原始圖片大小。 這會減小過渡延遲,由於原始圖片會存在於內存中,不會在磁盤緩存中。注意:此操做會讓你的的程序變慢,須要當心使用。若是你必定要這樣作的花,這裏有個修改的分支能夠參考下.
如今能夠正常使用了,但在一些錯誤連接圖片獲取未加載完成但圖片就會有一個小問題。
咱們要在任何條件下均可以無縫過渡,最簡單的方式是從緩存中獲取圖片 (或者若是圖片未加載完成時, 就使用佔位圖)。 DetailActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
...
detailImage.load(url, loadOnlyFromCache = true) {
supportStartPostponedEnterTransition()
}
}
複製代碼
fun ImageView.load(url: String, loadOnlyFromCache: Boolean = false, onLoadingFinished: () -> Unit = {}) {
...
val requestOptions = RequestOptions.placeholderOf(R.drawable.placeholder)
.dontTransform()
.onlyRetrieveFromCache(loadOnlyFromCache)
...
}
複製代碼
固然,這意味着用戶打開詳情頁面時,在圖片加載完成以前,只會顯示佔位圖。它會在過渡結束後經過第二次請求來修復:
DetailActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
...
window.sharedElementEnterTransition = TransitionSet()
.addTransition(ChangeImageTransform())
.addTransition(ChangeBounds())
.apply {
doOnEnd { detailImage.load(url) }
}
}
複製代碼
最終,咱們有了一個很是棒的過渡轉場效果,它能夠工做在各類條件下。您能夠在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