見出し画像

Androidアプリ『おりこうちょきん』開発日記 【その2】ボタンのクリックイベントを実装する

今回のヘッダーはサイケなブラキオサウルス©長男です。
透過画像だとうまくサイズ調整できないなぁ。

画像1

【その1】にて、TableLayoutとImageButtonを使ってスタンプカードのマス目を作りました。
今回はそれらのボタンにクリックイベントを実装します。

MainActivity.java 基本の「き」

前回はactivity_main.xmlがメインでしたが、今回はMainActivity.javaがメインです。(ややこしい)
まず「空のアクティビティ」初期状態のコードを載せます。

package hoge.fuga.sandbox;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

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

onCreate()は、アプリ起動時に走る初期処理です。
setContentView(R.layout.activity_main)は、「activity_main.xmlで設定した画面デザインをアプリの画面としてセットする」ということです。activity_main.xmlとは別に画面デザインのxmlファイル「hoge.xml」を定義しておいて、setContentView(R.layout.hoge)と記述したらそちらがアプリの画面になります。

R(おそらくResourceの頭文字)はAndroidStudioが内部的に生成するクラスです。アプリ上の要素(Viewなど)を列挙してIDを振って管理しているものと理解しています。

ボタンにクリックイベントを実装する方法

ボタンにクリックイベントを実装する方法は(私が把握している限りで)2通りあります。
● ボタンのandroid:onClickプロパティを使う方法
● ボタンにsetOnClickListenerする方法
です。
一つ目の方法については以下に記載しています。

ここでは二つ目の方法でボタンにクリックイベントを実装していきます。

ボタンにsetOnClickListener()しよう

まず、MainActivity.javaの中で、activity_main.xmlに定義したボタンを扱うために変数を用意します。
おそらくクラス内のあちこちで使う変数なので、メソッドのローカル変数ではなく、クラスのメンバ変数として定義します。
ImageButtonと入力すると候補としてImageButton android.widgetが出てくるので、Tabキーを押して決定します。

画像3

package hoge.fuga.sandbox;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.widget.ImageButton; //★2

public class MainActivity extends AppCompatActivity {

   ImageButton myImageButton1; //★1

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

★1:myImageButton1という名前でImageButton型の変数を定義しています。
★2:ImageButtonを定義する(★1)とimportを自動生成してくれます。

次にこのmyImageButton1にactivity_main.xmlの情報を持ってきます。
これにはfindViewById()を使います。

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

       myImageButton1 = findViewById(R.id.imageButton); //★3
   }

★3:findViewById()の引数に、Rクラスに列挙されているViewのIDを指定して情報を取得します。ちなみに「R.id.imageButton」は前回一番左上に配置したボタンを指します。

画像3

このボタンにクリックリスナーをセットします。「クリックしたことを聞き取るための耳をつける」というかんじ?
myImageButton1.set…と入力すると候補にsetOnClickListener()が出てきます。

画像4

引数はOnClickListenerクラス?(先頭が大文字なのでクラスだと判断)じゃあそのクラスをnewしてインスタンス化しようということでnew On…と入力すると候補にView.OnClickListenerが出てきます。アイコンが緑丸の「I(アイ)」なのでクラスではなくインターフェース(Interface)だと分かります。

画像5

Tabキーで決定すると以下のようにコードが自動生成されます。

import android.view.View;
        myImageButton1.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {

           }
       }); //ここのセミコロンは自分で入力しました。

正直「ええ?なんだなんだ、何が起こってるのか分からない!」と思いました。android.view.Viewクラスをimportしたことだけは分かる。

インターフェース(Interface)とはなんだ

まずインターフェースとはなんぞや、というところからで、以下の記事がとても分かりやすい。

端的に説明された一文を引用します。

インターフェースは「このクラスは、○×△メソッド(≒関数)を持ちます!」という「約束」です

つまり「Viewクラス内にOnClickListenerというインターフェースが定義されていて、OnClickListenerはonClcik()メソッドを持つことを約束しています」ということ?それを確かめるべく、パッケージ > ライブラリー > Android > view > View を展開します。

Viewクラスはどこ?

▲Viewクラスまでの道のりGifアニメーションです。

画像7

見つけました。確かにonClick()メソッドを持つことを約束しています。約束を破るとエラーになります。
あーそーゆーことね、完全に理解した。

インターフェースのonClick()には中身がないので、オーバーライドして自分で定義します。
android.widget.Toastクラス(VBでいうとMessageBox)を使って、ボタンをクリックしたらメッセージが出るようにします。

import android.widget.Toast; 
        myImageButton1.setOnClickListener(new View.OnClickListener() {
           @Override
           public void onClick(View view) {
               Toast.makeText(MainActivity.this, "ボタンをクリックしました", Toast.LENGTH_SHORT).show();
           }
       });

この状態でビルドしてAPKを生成し、自分のスマホにデプロイしました。

(開発マシンが仮想デバイスに対応しているなら、わざわざデプロイする必要はないと思います。私のマシンは仮想デバイス未対応です…。)
それを起動して一番左上のボタンをクリック(タップ)した状態をスクリーンショットしました。

画像8

成功です!
ちなみにこれは匿名クラスを使った方法だそうです。次から次へと難しい言葉が出てくるJava…。

匿名クラスとはなんだ

まずは以下の記事を読んで理屈を頭に入れます。

通常、クラスは「宣言(定義)」と「利用」が分かれています。
一方、匿名クラスでは、(中略)「宣言」と「利用」を一度に行います。

理屈は分かるものの、うーん。
ということで、先ほどの匿名クラスで記述されたコードを、敢えて通常のクラスに書き換えてみます。

public class MainActivity extends AppCompatActivity {

   ImageButton myImageButton1;

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

       myImageButton1 = findViewById(R.id.imageButton);

//        myImageButton1.setOnClickListener(new View.OnClickListener() {
//            @Override
//            public void onClick(View view) {
//                Toast.makeText(MainActivity.this, "ボタンをクリックしました", Toast.LENGTH_SHORT).show();
//            }
//        });
       
       myImageButton1.setOnClickListener(new MyOnClickListener());
   }

   class MyOnClickListener implements View.OnClickListener {
       @Override
       public void onClick(View view) {
           Toast.makeText(MainActivity.this,"ボタンをクリックしました", Toast.LENGTH_SHORT).show(); //★7
       }
   }
}

匿名クラスを使っている箇所はコメントアウトしています。
この記述で、匿名クラスで実装したのと同じ動作を確認できました。
まず、クラス定義をした箇所を抜粋して偉そうに解説します。

   class MyOnClickListener implements View.OnClickListener {
       @Override
       public void onClick(View view) {
           Toast.makeText(MainActivity.this,"ボタンをクリックしました", Toast.LENGTH_SHORT).show(); //★7
       }
   }

クラスの名前は「MyOnClickListener」としています。
implementsは「このクラスでView.OnClickListenerインターフェースを実装(=implements)します」という意味です。View.OnClickListenerインターフェースとの約束「onClick()を実装する」を果たしているわけです。

次に、そのクラスをインスタンス化して使う箇所を抜粋します。

       myImageButton1.setOnClickListener(new MyOnClickListener());

この「MyOnClickListener」クラスを他で使う予定がないなら、匿名クラスの記述で十分だ、ということらしいです。匿名クラスのメリットは他にもあるのでしょうが、今の理解はここまで。

ちなみに、匿名クラスであろうと通常のクラスであろうと、インターフェースとの約束を果たすためにAndroidStudioが記述を補完してくれます。
中身のないクラスを作ると、約束が果たされていないので赤い電球が出てきます。そこに「メソッドの実装」があるのでクリックします。

画像9

すると、「実装するメソッドの選択」ダイアログが起動するので、実装するメソッドonClick()を選択します。

画像10

画像11

これで後はonClick()の処理を記述すればいい状態になりました。

「Javaは制限だらけ」だからこそいい

匿名クラスのメリットについて検索したら、以下がヒットしました。

この質問への回答冒頭にこうあります。

Javaは制限だらけ

よくJavaは難しいと言われるし、実際今とても苦戦していますが、それは「制限だらけ」だからなんですね。その制限に関するルールを知らないことにはプログラムが書けない、読めない。
これは、プログラミングが好きで、自分なりによく書けたコードをうっとり眺めたりするタイプの人(私)にとってはメリットだと思います。制限が多ければ多いほど、誰が書いてもある程度の質が確保されるはずだからです。やりたい放題書けてしまうVB.NETなどを敬遠する声を見かけたことがありますが、なるほどそういうことかと思いました。

クリックイベントは実装できたが…

クリックイベントの実装方法は分かりました。
が、マス目に並べた大量のボタン全てにこれをやらなければならないので、スマートなやり方を検討しなければなりません。
次回は大量のボタンにクリックイベントを実装する過程を記録します。

👈To Be Continued…

この記事が気に入ったらサポートをしてみませんか?