Kotlinを使ってアプリで画像を表示させてみましょう。
画像表示にはImageView を使いますが画像の取り込み方による3種類の方法を試します。
2024.1.1
ImageView
JavaでのImageViewの基本的なところは以下を参照してください。
画像を3つ用意しスマホに表示させてみます
レイアウトに直接
drawableから読込
assetsから取込
img_1.jpg、img_2.jpgの2枚をdrawableにコピー&ペーストして入れています。
また残りの、img_3.jpg を「assetsフォルダを作成して」入れます。
(assetsフォルダの設定は後半に説明があります)
レイアウトに直接埋め込むケース
これは、最初からレイアウトに記述します。
drawable に img_1.jpg を入れた状態で、レイアウトファイル activity_main.xml には以下のようにします。
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:src="@drawable/img_1" android:contentDescription="@string/img_description" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
リソースファイル
res¥values¥strings.xml
1 2 3 4 |
<resources> <string name="button">Your App Name</string> <string name="img_description">image</string> </resources> |
以上の設定でMainActivityはそのままで実行させると
画像が表示されました。
1 |
android:src="@drawable/img_1" |
drawableにある画像 img_1.jpg をsourceとして表示する設定です。(jpg, pngの拡張子はいりません)
1 |
android:contentDescription="@string/img_description" |
これは、contentDescriptionを入れろというワーニングに対応したものです。この画像の説明を入れるわけですが、なくてもBuildエラーにはなりません。
@Stringの im_description を呼び出していますが、呼び出し元はstrings.xmlに記述します。
res¥values¥strings.xml
1 2 3 4 |
<resources> <string name="button">YourAppName</string> <string name="img_description">image</string> </resources> |
画像を画面いっぱいに表示させるための設定です。
1 2 |
android:layout_width="match_parent" android:layout_height="match_parent" |
この場合は、MainActivity.java に何も記述する必要はないのでJavaもKotlinも同じです。
drawable にある画像を読み込む
上と同様に画像 img_2.jpg は同じく drawableにあるとして、そのIDコードを呼びだし setImageResource(ID) で表示します。
コードで画像を呼び出しているので動的に画像の変更ができます。
Javaの場合
1 2 |
ImageView imageView2 = findViewById(R.id.image_view_2); imageView2.setImageResource(R.drawable.img_2); |
Kotlinの findViewById ではこのようになります
1 2 |
val imageView2: ImageView = findViewById(R.id.image_view_2) imageView2.setImageResource(R.drawable.img_2) |
View Binding ではこのようになります
1 |
binding.imageView2.setImageResource(R.drawable.img_2) |
レイアウトは、MainActivityで呼ばれるIDに対応させます
1 2 3 4 |
<ImageView android:id="@+id/image_view_2" ... /> |
View Binding を使ってまとめるとこうなります
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//package com.example.kotlinimageview import android.os.Bundle import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import com.example.kotlinimageview.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } binding.imageView2.setImageResource(R.drawable.img_2) } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <ImageView android:id="@+id/image_view_2" android:contentDescription="@string/img_description" android:scaleType="centerCrop" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
リソースファイルです
res¥values¥strings.xml
1 2 3 4 |
<resources> <string name="button">Your App Name</string> <string name="img_description">image</string> </resources> |
build.gradle
1 2 3 4 5 6 7 8 |
... android { ... buildFeatures { viewBinding = true } } ... |
assets に画像を置きそれを取り込む場合
assets folder を作ります
「app」右クリック「New」「Folder」「Assets Folder」
そのまま「Finish」
できた assets に画像 img_3.jpg をコピー&ペーストします。
プロジェクトの階層内に入り、フォルダに直接入れることもできます。
..¥app¥src¥main¥assets¥img_3.jpg
assets からはファイルの読み出しはtry catchを使って例外処理をするようにします。
画像を取り込む記述は resources.assets.open() を使って このようにします。
1 2 3 4 5 6 7 8 9 10 |
binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) try { resources.assets.open("img_3.jpg").use { istream -> val bitmap = BitmapFactory.decodeStream(istream) binding.imageView3.setImageBitmap(bitmap) } } catch (e: IOException) { throw RuntimeException(e) } |
レイアウトは、指定されたID(image_view_3)を使います
1 2 3 |
<ImageView android:id="@+id/image_view_3" ... /> |
View Binding を使ってまとめると
MainActivity.kt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//package com.example.testimageview3 import androidx.appcompat.app.AppCompatActivity import android.os.Bundle // ViewBinding プロジェクトは TestImageView3 として作成した場合 import com.example.testimageview3.databinding.ActivityMainBinding import android.graphics.BitmapFactory import java.io.IOException class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) try { resources.assets.open("img_3.jpg").use { istream -> val bitmap = BitmapFactory.decodeStream(istream) binding.imageView3.setImageBitmap(bitmap) } } catch (e: IOException) { throw RuntimeException(e) } } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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_3" android:contentDescription="@string/img_description" android:scaleType="centerCrop" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
strings.xml
1 2 3 4 |
<resources> <string name="button">Your App Name</string> <string name="img_description">image</string> </resources> |
build.gradle
1 2 3 4 5 6 7 8 |
... android { ... buildFeatures { viewBinding = true } } ... |
画像が表示されましたでしょうか
drawable VS assets
なぜdrawableだけでなくassetsを使うかというと、
- アイコン画像などを100個以上使うようなケースでassetsではフォルダ分けができます。drawableではベタで放り込むしかありません。
- assetsからの取り込みの場合はBitmapFactoryを使って画像をダウンサンプリリングすることができるためdrawableよりは比較的大きいファイルを取り込めます。
画像サイズというのはファイルサイズではなく、画像の横 x 縦なので圧縮は関係ありません。なぜならbitmap変換するところがネックなので。
メモリのリミットはAndroidの場合、端末依存なのでこれで大丈夫とは言い切れないのも困ったことで、最近はスマホも昔のPC並になりましたが、ハイエンドからローエンドまで存在するのが悩みです。
また、大きいサイズの画像を使う場合はassetsではなくアプリ固有の外部ストレージや共有の外部ストレージに保存して使用するケースが最近では多いかもしれません。
Reference:
ImageView | Android Developers