KotlinでAndroidの Button アプリを簡単に作ってみました。
findViewByIdの代わりにAndroid Kotlin Extensions プラグインを使っていましたが、現在では ViewBinding が推奨されています。
2024.1.1
Button
JavaでのButtonアプリを下のように作成しましたが、
その作り方を参考にKotlinに変えてみます
Button
Buttonの基本的な設定はこのようになります、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import android.widget.Button class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { val button: Button super.onCreate(savedInstanceState) ... button = findViewById(R.id.button) // クリック button.setOnClickListener { ... } } } |
実際にエミュレータで実行するために、まとめてみます
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
//package com.example.kotlinbutton import android.os.Bundle import android.widget.Button import android.widget.TextView import androidx.activity.enableEdgeToEdge import androidx.appcompat.app.AppCompatActivity import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { val button: Button val textview: TextView super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main) ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } // Button切り替え用のフラグ var flag = false textview = findViewById(R.id.textview) button = findViewById(R.id.button) button.setOnClickListener { if (flag ) { // flagがtrueの時 textview.text = getString(R.string.hello) flag = false } else { // flagがfalseの時 textview.text = getString(R.string.world) flag = true } } } } |
レイアウトはこのように設定してみます
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 23 24 25 26 27 28 29 30 31 32 33 |
<?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"> <TextView android:id="@+id/textview" android:text="@string/hello" 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:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/button" android:text="@string/button" 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:layout_constraintVertical_bias="0.5" /> </androidx.constraintlayout.widget.ConstraintLayout> |
直に書いていると後でハマることになります。(と理解してけっこうやっていましたが)最近はうるさくワーニングが出るのでちゃんとしてみました。
strings.xml のファイルは以下の場所にあります。
strings.xml
1 2 3 4 5 6 |
<resources> <string name="app_name">KotlinButton</string> <string name="hello">Hello</string> <string name="world">World</string> <string name="button">Button</string> </resources> |
以下を参考にエミュレータを作成してください。
デフォルトでエミュレータがAndroid Studio内に表示されますが
設定を変えれば独立させることも可能ではあります。
これでボタンをタップすると、Hello、Worldと切り替わります
View Binding
findViewById を使ってXMLレイアウトファイルからIDを読みだしていたのを
View Binding を使ってビューを操作するコードを簡単に記述できます
Migrate from Kotlin synthetics to Jetpack view binding
View Binding:
セットアップとして、build.gradle ファイルに viewBinding 要素を追加します。
build.gradle
1 2 3 4 5 6 7 |
android{ ... buildFeatures { viewBinding = true } } |
プロジェクトのXML レイアウトファイルが
activity_main.xml
の場合は、そのレイアウトファイル毎にViewBinding Class を作成します。
1 2 3 |
package com.example.kotlinbutton ... import com.example.kotlinbutton.databinding.ActivityMainBinding |
[package name].databinding.[XMLレイアウトファイル名から]Binding
ActivityMainBindingはXMLファイルの名前(activity_main)を
キャメルケースに変換して、末尾に「Binding」という単語を追加することで生成します。
例)
activity_main.xml | >> | ActivityMainBinding |
sub_layout.xml | >> | SubLayoutBinding |
main.xml | >> | MainBinding |
Viewのidでは
text_view | >> | textView |
textview | >> | textview |
button | >> | button |
Activityでの使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// ViewBinding Class のインスタンス // lateinit で宣言し初期化タイミングを onCreate() まで遅らせる private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // bindingのイニシャライズ // Binding Classに含まれる静的 inflate() メソッドを呼び出す binding = ActivityMainBinding.inflate(layoutInflater) // root view への参照を取得 val view = binding.root // view をsetContentView()にセット setContentView(view) binding.button.setOnClickListener { ... } } |
サンプルコード
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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
//package com.example.kotlinbutton 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.kotlinbutton.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 } // Button切り替え用のフラグ var flag = false binding.button.setOnClickListener { if (flag ) { // flagがtrueの時 binding.textview.text = getString(R.string.hello) flag = false } else { // flagがfalseの時 binding.textview.text = getString(R.string.world) flag = true } } } } |
レイアウトファイル、リソースは同じです
次にbuild.gradleですが2つあるので注意してください
Module:App の方です
build.gradle
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 28 |
plugins { ... } android{ compileSdk ... defaultConfig { ... } buildTypes { release { ... } } compileOptions { ... } kotlinOptions { ... } buildFeatures { viewBinding = true } } ... |
android { } の中にbuildFeatures{ } を追加します。
記述後には Sync が必要です(エディタ上部に表示が出ます)
反映に多少時間がかかる場合もあります(MainActivityのエラーの赤線が消えるまで時間がかかる数十秒?)
これで実行してボタンが表示されましたでしょうか
ちょっと見栄えをよくしてみます
フォントを大きくしたりレイアウトを変更したり
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 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?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"> <TextView android:id="@+id/textview" android:text="@string/hello" android:textSize="50sp" android:textColor="#ff00ff" 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:layout_constraintVertical_bias="0.4" /> <Button android:id="@+id/button" android:text="@string/button" android:textSize="30sp" 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:layout_constraintVertical_bias="0.6" /> </androidx.constraintlayout.widget.ConstraintLayout> |
これで実行してみると
Kotlinでは生産性が上がるという意見もありますが、どうでしょう。今後のGoogleにおけるJavaの扱いがどうなるか、どうなっても対応できるようにしておいた方がいいのかもしれません
References:
ボタン | Android デベロッパー
Kotlin and Android | Android Developers
Kotlin Programming Language
Kotlin Android Extensions の未来
Use view binding to replace findViewById