為何要使用 Coil
想要顯示圖片,需先將圖片下載、儲存、解碼等等,為獲取最佳效能,建議一次擷取多張圖片並解碼。工作繁雜,所以建議使用 Coil 幫忙處理。
Coil 使用的預備工作
Coil 需要 :
- 圖片網址
- 顯示圖片的 ImageView 物件
添加依附元件
implementation "io.coil-kt:coil:1.1.1"
為何要使用 Binding Adapter (資料繫結器)
舉例 :
使用 android:text="Sample Text" , Android 系統會自動尋找 test 的 settter 方法
setText(String: text)
(尋找傳入參數是 String 的是因為傳給屬性的是 String)。若找不到則會發生錯誤。若在 ImageView 元件使用自訂的屬性 app:imageUrl="@{product.imageUrl}" ,系統會在 ImageView 中尋找 setImageUrl(String) 方法。為了讓系統可以找到,所以要使用繫結轉接器 (註解方法) ,將 app:imageUrl 屬性設為 ImageView。
例子 : 用BindingAdapter 搭配 Coil 的 load 根據 URI 載入圖片
//寫做頂層函式
@BindingAdapter("imageUrl") //傳入屬性名稱,當view有此屬應時會自動執行此 binding adapter
fun bindImage(imageView: ImageView, imageUrl: String?){ //第一個參數是方法的接收者(view),第二個是傳給屬性的參數
imageUrl?.let {
val imgUri = imageUrl.toUri() //將字串轉成 Uri 物件
.buildUpon().scheme("https") //使用 HTTPS 配置
.build()
//使用 Coil 的 load(){} 將 imgUri 物件的圖片載入 imgView。
imageView.load(imgUri)
}
}
<ImageView
...
app:imageUrl="@{viewModel.photos.imgSrcUrl}"
... />
設置 loading 與載入錯誤的圖片
使用 Coil 不僅可以顯示預留位置圖片,還能載入圖片,如果因圖片缺失或損毀等原因造成載入失敗,也可以載入錯誤圖片,進而改善使用者體驗。
使用方式 : 將前面程式碼中的 load 添加載入中與載入錯誤的圖片
@BindingAdapter("imageUrl") //傳入屬性名稱,當view有此屬應時會自動執行此 binding adapter
fun bindImage(imageView: ImageView, imageUrl: String?){ //第一個參數是方法的接收者(view),第二個是傳給屬性的參數
imageUrl?.let {
val imgUri = imageUrl.toUri() //將字串轉成 Uri 物件
.buildUpon().scheme("https") //使用 HTTPS 配置
.build()
//使用 Coil 的 load(){} 將 imgUri 物件的圖片載入 imgView。
//imageView.load(imgUri)
imageView.load(imgUri) {
placeholder(R.drawable.loading_animation) //loading 時顯示 loading 圖片
error(R.drawable.ic_broken_image) //圖片載入失敗則顯示錯誤圖片
}
}
}
但添加後只會顯示每張圖片的 loading 或正常顯示圖片,並不會在沒有網路的時候顯示錯誤。
若要顯示錯誤,可在添加一個專門顯示錯誤的 ImageView,正常顯示時才隱藏此 view。如下方例子(此例除了顯示錯誤,也會在 loading 時顯示 loading 圖片):
<ImageView
android:id="@+id/status_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:marsApiStatus="@{viewModel.status}" />
@BindingAdapter("marsApiStatus")
fun bindStatus(statusImageView: ImageView,
status: MarsApiStatus?) {
when (status) {
MarsApiStatus.LOADING -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.loading_animation)
}
MarsApiStatus.DONE -> {
statusImageView.visibility = View.GONE
}
else -> {
statusImageView.visibility = View.VISIBLE
statusImageView.setImageResource(R.drawable.ic_connection_error)
}
}
}
enum class MarsApiStatus { LOADING, ERROR, DONE }
...
private fun getMarsPhotos() {
_status.value = MarsApiStatus.LOADING
viewModelScope.launch {
try{
_photos.value = MarsApi.retrofitService.getPhotos()
_status.value = MarsApiStatus.DONE
} catch (e: Exception) {
_status.value = MarsApiStatus.ERROR
_photos.value = listOf()
}
}
}
0 comments:
張貼留言