Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

[Android] 画像読み込みライブラリ Coil でできることまとめ

More than 1 year has passed since last update.

Coil の良いところ

Coil は Kotlin コルーチンを利用した Android 用の画像読み込みライブラリです。
公式サイトにもありますが、次のような良いところがあるそうです。

image.png

特徴 内容
処理が早い メモリキャッシュ、ディスクキャッシュ、画像のダウンサンプリング、
ビットマップの再利用、画像読み込みリクエストの一時停止やキャンセルなど
様々な最適化を含めているので効率がよく早い
サイズが軽い CoilはPicassoとGlide、Frescoと同等の機能を持つが、
1500メソッドぐらいのライブラリでサイズが軽い
簡単に使える Kotlinの言語機能を使ってAPIをシンプルに使いやすくしている
モダンな技術を使っている Kotlinファーストで、CoroutineやOkHttp、Okio、AndroidXなどの
モダンなライブラリを利用して開発している。

Coil のセットアップ

次の内容を build.gradle(app) に記述して Coil をインストールする。

build.gradle(app)
dependencies {
    implementation 'io.coil-kt:coil:0.8.0'
                  ︙
}

今回はインターネットにアクセスするので、
次のパーミッションを AndroidManifest.xml に記述しておく。

AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="kaleidot725.coilsample">
    <uses-permission android:name="android.permission.INTERNET" /></manifest>

Coil で ImageView に画像を読み込む

次のようなレイアウトを定義し、ImageView に色々な方法で画像を読み込んでみる。
image.png

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/image_view"
        android:layout_width="300dp"
        android:layout_height="300dp"
        android:layout_gravity="center"
        android:background="#CCCCCC"/>

    <Button
        android:id="@+id/reload_button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="right|bottom"
        android:layout_margin="16dp"
        android:text="Reload"/>
</FrameLayout>

ただ単純に画像を読み込む

imageViewの後にloadと記述しurlを指定するだけで画像を読み込める。
String だけでなく HttpUrl Url File DrawableRes Int Drawable Bitmap などを指定できる。
あとImageView.load では Disposable を返すので、それを使えば読み込みをキャンセルできるようになっている。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
           val disposable = imageView.load(url)
           disposable.dispose()
        }

Nov-28-2019 00-21-05.gif

画像を読み込むときにクロスフェードする

crossfadetrue にするだけで読み込み時にクロスフェードさせることができる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                crossfade(true)
            }
        }

Nov-28-2019 00-23-10.gif

画像を読み込むときにクロスフェードの秒数(ms)を指定する

クロスフェードのありなしを指定するだけでなく、
時間を指定することで何ミリ秒かけてクロスフェードするか決められる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                crossfade(3000)
            }
        }

Nov-28-2019 00-27-44.gif

プレースホルダー画像を設定する

プレースホルダーを設定できる。
次のように読み込み中、クロスフェード中に画像が表示されるようになる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                placeholder(R.drawable.placeholder)
                crossfade(3000)
            }
        }

Nov-28-2019 08-45-50.gif

エラー画像を設定する

エラー画像を設定できます。
次のように読み込みに失敗したときに画像が表示されるようになる。

MainActivity.kt
        val url = "https://hoge.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                error(R.drawable.error)
            }
        }

Nov-28-2019 08-52-01.gif

読み込み画像を加工する

Coil では読み込んだ画像を加工する機能がある。
Blur CropCircle grayscale rouded corners と4種類の加工ができる。

Blur

次のようにガウシアンフィルターをかけてぼかしが効いた画像を表示できる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                transformations(BlurTransformation(context = applicationContext, radius = 5f, sampling = 5f))
            }
        }

Nov-28-2019 08-59-23.gif

CropCircle

円形に画像をクロッピングできる。
次のように画像の一部を円形でクロッピングして表示できる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                transformations(CircleCropTransformation())
            }
        }

Nov-28-2019 09-14-09.gif

Grayscale

次のように画像をグレースケールで表示できる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                    transformations(GrayscaleTransformation())
            }
        }

Nov-28-2019 22-41-22.gif

Rounded Corner

次のように角を丸めた画像を表示できる。
topRight topLeft bottomeLeft bottomRight とそれぞれの角の丸めを調整できる。

MainActivity.kt
        val url = "https://www.underconsideration.com/brandnew/archives/android_2019_logo_inverse.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url) {
                transformations(RoundedCornersTransformation(topRight = 10f, topLeft = 10f, bottomLeft =  10f, bottomRight =  10f))
            }

Nov-28-2019 22-50-19.gif

Coil では Image Loader でキャッシュ設定など変更できる

次のように Coil では ImageLoader を生成することであらかじめどの設定で画像を読み込むか決められる。
例えば 今まで紹介した機能もここに記載しておきますし、Memory Cache や Bitmap Pooling などの細かな設定もできる。

MainActivity.kt
        val imageLoader = ImageLoader(applicationContext) {
            crossfade(true)
            placeholder(R.drawable.placeholder)
            error(R.drawable.error)
            availableMemoryPercentage(0.1)
            bitmapPoolPercentage(0.1)
        }

次のように作成した ImageLoaderload の引数に与えることで、
ImageLoader に設定した内容を利用して画像を読み込むことができる。

MainActvitiy.kt
        val imageLoader = ImageLoader(applicationContext) {
            crossfade(true)
            placeholder(R.drawable.placeholder)
            error(R.drawable.error)
            availableMemoryPercentage(0.1)
            bitmapPoolPercentage(0.1)
        }
        val url = "https://notfound.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url, imageLoader)
        }

Nov-28-2019 23-27-44.gif

上記のように load の引数に指定するのが面倒なのであれば、
次のように Coil.setDefaultImageLoader で作成した
ImageLoader をデフォルトとして設定しておくこともできる。

MainActivity.kt
        Coil.setDefaultImageLoader(ImageLoader(applicationContext) {
            crossfade(true)
            placeholder(R.drawable.placeholder)
            error(R.drawable.error)
            availableMemoryPercentage(0.1)
            bitmapPoolPercentage(0.1)
        })

        val url = "https://notfound.png"
        val imageView = findViewById<ImageView>(R.id.image_view)
        val reloadButton = findViewById<Button>(R.id.reload_button)
        reloadButton.setOnClickListener {
            imageView.load(url)
        }

Nov-28-2019 23-33-09.gif

参考文献

kaleidot725
組み込みエンジニア ➔ Androidエンジニアになりました。なので最近は主に Android やってます。あとはサーバーサイド Kotlin もやっていこうと思っています。
https://medium.com/kaleidot725
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away