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

この記事は「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](https://qiita-image-store.s3.amazonaws.com/0/135833/9c7e7637-91de-cde3-75a8-4fc4deba8f78.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の魅力と記法について細かく書かれています

- [Android開発を受注したからKotlinをガッツリ使ってみたら最高だった](https://qiita.com/omochimetaru/items/98e015b0b694dd97f323)

# 次回予告

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

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