Help us understand the problem. What is going on with this article?

Androidアプリ開発(Java, Kotlin両対応) これどうやって実装するんだっけ? 〜Button編〜

More than 1 year has passed since last update.

この記事は「Androidアプリ開発 これどうやって実装するんだっけ?」の第一回です。

メインターゲットは私のような「そろそろググることを覚えた初中級者」を(勝手に)想定しています。

JavaとKotlinの両方について解説しているので、「Javaでの実装はわかるけど、Kotlinだとどう書くの?」という人にも
お役に立つかと思います。

本企画のサンプルは下のリンクにあります。masterブランチがKotlinのソースコード、javaブランチがJavaのソースコードです。

https://github.com/Dai1678/SampleCodePrograms

Buttonの実装

Androidアプリ開発を始めてまず最初に感動するところかと思っています。

サンプルとして、

  • Buttonを押したらtextが変わる
  • Floating Action Buttonを押したらSnack barが表示される

というのをやってみました。

環境

Android Studio 3.0+
Android 8.0で動作確認

Floating Action Buttonを使うので、Gradleファイルに以下の文を追加してください。

build.gradle
apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 27
    defaultConfig {
        applicationId "net.ddns.dai.samplecodeprograms"
        minSdkVersion 15
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    implementation 'com.android.support:appcompat-v7:27.1.0'
    implementation 'com.android.support.constraint:constraint-layout:1.0.2'
    implementation 'com.android.support:design:27.1.0'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'com.android.support.test:runner:1.0.1'
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
}

動作デモ

ButtonSampleActivity.gif

XMLの解説

rootタグを何にするかでFloatingActionButton周りの書き方が少し違ってきます。
作っているアプリのレイアウトに合わせて見てください。

  • LinearLayoutのとき
activity_button_sample.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="vertical"
    tools:context="net.ddns.dai.samplecodeprograms.ButtonSampleActivity">

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Buttonの実装について" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical">

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:id="@+id/changeText"
                android:text="押してください"/>

            <Button
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_horizontal"
                android:id="@+id/textChangeButton"
                android:text="Button"/>

         </LinearLayout>

         <android.support.design.widget.FloatingActionButton
             android:id="@+id/fab"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:layout_gravity="bottom|end"
             android:layout_margin="@dimen/fab_margin"
             app:srcCompat="@android:drawable/btn_star" />

         <!-- @dimen/fab_margin -> 16dp -->

     </FrameLayout>

</LinearLayout>

大事なところはコンテンツ部分をFrameLayoutで囲っているところ。
FrameLayoutはViewを重ねて表示したいときに使います。Floating Action Buttonがあるからね。
注意しなければならないのは、このLayout内のコンポーネントは位置指定ができない(全部左上に表示)ので、
この中にLinearLayoutを入れるなどしてコンポーネントを配置していってください。

この場合のFloating Action Buttonの位置指定は、android:layout_gravity="bottom|end"とするとイイ感じになります。

  • RelativeLayoutのとき

相対位置での配置ができるので、FrameLayoutを使わなくても大丈夫です。位置指定は↓の感じでやれば大丈夫。

activity_button_sample.xml
<android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_margin="@dimen/fab_margin"
        app:srcCompat="@android:drawable/ic_dialog_email" />
  • CoordinatorLayoutのとき

後々の回で説明しますが、FloatingActionButtonについてはRelative Layoutと同様に考えてもらって大丈夫です。
Activityを新規作成するときにBasic Activityを選択するとデフォルトでこれが使われています。
さらにかっこよく使いたい人はこっちを使うと良いかも?

Activityの解説

buttonの処理については様々な記述方法があると思います。
僕が使い分けているのは2通り。
JavaとKotlinでそれぞれソースコードを交えて簡単に解説します。

Java編

  • Button処理が一つの場合 (例としてFloatingActionButtonを省略しています)
ButtonSampleActivity.java
public class ButtonSampleActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_sample);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        boolean flag = false;

        Button button = findViewById(R.id.textChangeButton);
        button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View view) {
                TextView textView = findViewById(R.id.changeText);

                if (flag){
                    textView.setText("押してください");
                    button.setText("BUTTON");
                    flag = false;

                }else{
                    textView.setText("Buttonが押されました!");
                    button.setText("戻す");
                    flag = true;
                }
             }
         });
    }
}

多くのWebサイトで掲載されているサンプルコードやAndroid Developersなどでよく紹介されているやり方です。
onCreateメソッド内で匿名クラスを使っています。
Buttonが1,2個とかであればこのやり方で済ませて良いと思います。

  • Button処理が複数ある場合
ButtonSampleActivity.java
public class ButtonSampleActivity extends AppCompatActivity implements View.OnClickListener {

    Button button;
    boolean flag = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_button_sample);

        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null){
            actionBar.setDisplayHomeAsUpEnabled(true);
        }

        button = findViewById(R.id.textChangeButton);
        button.setOnClickListener(this);

        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(this);

    }

    @Override
    public void onClick(View view) {
        switch (view.getId()){

            case R.id.textChangeButton:
                TextView textView = findViewById(R.id.changeText);

                if (flag){
                    textView.setText("押してください");
                    button.setText("BUTTON");
                    flag = false;

                }else{
                    textView.setText("Buttonが押されました!");
                    button.setText("戻す");
                    flag = true;
                }

                break;

            case R.id.fab:
                Snackbar.make(view, "fabが押されました!", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
                break;
        }
    }
}

匿名クラスを使用しない場合は、OnClickListenerをimplementsします。まずは1行目のところに書いてください。
赤線でエラーが出ている場合、Android Studio上で赤バルーンがpublick void onClick(View view){}というメソッドを
作るよう要求してくるので、実行すれば自動的にメソッドを作ってくれます。(自分で記述しても可)

onClickメソッド内では、view.getId()でxmlで指定したButtonのidを取得して処理を分けています。

忘れがちなのがfindViewByIdと、setOnClickListener(this)です。気をつけて!
(Butter KnifeやData Bidingを利用すると簡略化できますが、既存の書き方から大きく変わってしまうのが嫌だったので
導入していません。)

Kotlin編

build.gradleにも書いてありますが、こちらではkotlin-android-extensionsを導入しています。
これがかなり便利で、xmlで指定したidの名前をそのまま利用でき、なおかつコード量もとても少なくできます。

  • Button処理が一つの場合
ButtonSampleActivity.kt
class ButtonSampleActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_button_sample)

        val actionBar = supportActionBar
        actionBar!!.setDisplayHomeAsUpEnabled(true)

        var flag = false

        //kotlin-android-extensionsのおかげでfindViewByIdの一文を書かなくてもxmlのidで指定できる!!
        textChangeButton.setOnClickListener { view ->
            flag = if (flag){
                    changeText.text = "押してください"
                    textChangeButton.text = "BUTTON"
                    false

                }else{
                    changeText.text = "Buttonが押されました"
                    textChangeButton.text = "戻す"
                    true
                }
        }

    }
}

Javaのソースコードよりすっごいスッキリしてますよね?
findViewByIdや無駄なnullチェック、onClick、そしてセミコロンがない!
よし今すぐKotlinを始めよう()

  • Button処理が複数ある場合
ButtonSampleActivity.kt
class ButtonSampleActivity : AppCompatActivity(), View.OnClickListener {

    private var flag = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_button_sample)

        val actionBar = supportActionBar
        actionBar!!.setDisplayHomeAsUpEnabled(true)

        //kotlin-android-extensionsのおかげでfindViewByIdの一文を書かなくてもxmlのidで指定できる!!
        textChangeButton.setOnClickListener(this)   
        fab.setOnClickListener(this)

    }

    override fun onClick(view: View) {

        when (view.id){     //switch文はないのでwhen文を使う
            R.id.textChangeButton -> {
                this.flag = if (flag){
                    changeText.text = "押してください"
                    textChangeButton.text = "BUTTON"
                    false

                }else{
                    changeText.text = "Buttonが押されました"
                    textChangeButton.text = "戻す"
                    true
                }
            }

            R.id.fab -> {
                Snackbar.make(view, "fabが押されました!", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show()
            }
        }
    }
}

こちらも同様にonClickメソッドをonCreateメソッドの外に書く手法です。
このソースコードについてJavaとの違いで気をつけたいのは、

  • implementsとは書かずにカンマで追加する
  • Kotlinにはswitch文が存在しないのでwhen文を使用
  • var, valの型推論

といったところでしょうか。

参考

Kotlinの魅力と記法について細かく書かれています

次回予告

TextViewやEditTextなどのテキスト周りを書きます。

あとがき

大学の後輩などにも見せたいですが、Qiitaユーザーの皆さんからも需要があればコメント頂けると嬉しいです
間違い等あれば修正リクエストの方して頂けると助かります。

daivr7774
Android、GAS、Node.jsあたりを雰囲気でやってる学生エンジニア Done is better than perfect. Just do IT !
https://github.com/Dai1678
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