神経衰弱アプリを作ってみる
8.並べたカードを表示する
さて前回はお勉強が長過ぎて、結局何をやったのか分からなかったよー!という人のために簡単にまとめとおさらい。
まずはシャッフルして12組24枚のカードをセットする部分、「setCard()」メソッドのコードを見直してみよう。
/**
* カードの配列にランダムに画像をセット
*/
private void setCards() {
//カードの表の画像(配列)・・・(A)
TypedArray images = getResources().obtainTypedArray(R.array.card_images);
//imageArrayを使って、すべての画像番号をシャッフルする・・・(B)
ArrayList<Integer> imageArray = new ArrayList<Integer>();
for ( int i = 0; i < images.length(); i++ ) {
imageArray.add(i);
}
Collections.shuffle(imageArray);
//cardArrayを使って、カードの数分の画像番号を取り出しシャッフルする・・・(C)
ArrayList<Integer> cardArray = new ArrayList<Integer>();
for ( int i = 0; i < ROW*COL/2; i++ ) {
cardArray.add(imageArray.get(i));
cardArray.add(imageArray.get(i));
}
Collections.shuffle(cardArray);
//カードの配列に、シャッフルした画像番号と画像をセットする・・・(D)
for (int i=0; i < ROW*COL; i++) {
card[i] = new Card(
cardArray.get(i),
images.getDrawable(cardArray.get(i))
);
}
}
(A)でカード画像を配列のオブジェクトとして生成、(B)で全カードの画像番号をシャッフルして(C)でそこから取り出した12枚の画像番号をペアにして24枚の画像番号をシャッフル。
そして(D)でカードクラスをインスタンス化して、シャッフルした画像番号とそれに対応する画像をセットしてるんだね。
そのセットの際にコンストラクタを使ってるってのは前回勉強したとおりなんだけれども、その部分を復習のためもう少しよく見てみようかな。
まず呼び出してるコンストラクタは、Cardクラスの定義を見ると分かるように
Card(int imgNo, Drawable cardImg)
っていう形式で、「imgNo」に画像番号を「cardImg」には画像を渡してやるように定義されてる。
で、上記のコードを見てみると画像番号としては
cardArray.get(i)
を渡しているのが分かるね。
これは、(C)で生成したオブジェクト「cardArray」から「i」番目の値を「get」メソッドを使って取得してるってことだ。
つまり、シャッフルした24枚のカードの「i」番目の画像番号をセットしてるってことになるんだね。
次に画像のほうだけれども、
images.getDrawable(cardArray.get(i))
としてセットしている。
これは「getDrawable」メソッドを使って、「images」という全カード画像の配列から「cardArray.get(i)」番目の画像を取得している。
「cardArray.get(i)」っていうのはその前にセットしている画像番号のことだから、つまり画像番号と対になっている画像そのものをセットしているってことが分かるでしょ。
これをforループでROW*COL=24回やって、結果12組24枚分の画像番号と画像をcardクラスのインスタンスを使った配列にセットしているのがこの(D)の処理の正体だ。
この処理はかなり大事な部分だから、シッカリ理解してくれ!頼む。
さて・・・JAVAの勉強もしたりしてずいぶん長くかかったけれども、以上でカードをランダムに並べる処理の説明は終了。
理解してもらえたかな。
では、いよいよ並べたカードを表示する処理を追加することにしよう。
変更する部分はプログラム中でたったの2ヶ所、下記の赤字の部分だけだ。
package android.test;
import java.util.ArrayList;
import java.util.Collections;
import android.app.Activity;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.view.Display;
import android.view.Menu;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.TableLayout;
import android.widget.TableRow;
public class AndroidTestActivity extends Activity {
static final int ROW = 6; //セルの行数・・・(1)
static final int COL = 4; //セルの列数・・・(2)
//カードの配列
Card[] card = new Card[ROW*COL]; //・・・(11)
@Override
public void onCreate(Bundle savedInstanceState) {
//ステータスバーを消去
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); //・・・(3)
//タイトルバーを消去
requestWindowFeature(Window.FEATURE_NO_TITLE); //・・・(4)
super.onCreate(savedInstanceState);
setCards(); //・・・(12)
TableLayout tableLayout = getTableLayout(); //・・・(5)
setContentView(tableLayout); //・・・(6)
}
/**
* カードの配列にランダムに画像をセット
*/
private void setCards() {
//カードの表の画像(配列)
TypedArray images = getResources().obtainTypedArray(R.array.card_images);
//imageArrayを使って、すべての画像番号をシャッフルする
ArrayList<Integer> imageArray = new ArrayList<Integer>();
for ( int i = 0; i < images.length(); i++ ) {
imageArray.add(i);
}
Collections.shuffle(imageArray);
//cardArrayを使って、カードの数分の画像番号をペアで取り出しシャッフルする
ArrayList<Integer> cardArray = new ArrayList<Integer>();
for ( int i = 0; i < ROW*COL/2; i++ ) {
cardArray.add(imageArray.get(i));
cardArray.add(imageArray.get(i));
}
Collections.shuffle(cardArray);
//カードの配列に、シャッフルした画像番号と画像をセットする
for (int i=0; i < ROW*COL; i++) {
card[i] = new Card(
cardArray.get(i),
images.getDrawable(cardArray.get(i))
);
}
}
/**
* テーブルレイアウトを返却
* @return TableLayout
*/
private TableLayout getTableLayout() {
int cellNum = ROW * COL; //全体のセルの数
TableLayout tableLayout = new TableLayout(this);
TableRow tableRow = null;
for (int i = 0; i < cellNum; i++) {
if (i % COL == 0) {
tableRow = new TableRow(this);
tableLayout.addView(tableRow);
}
Button button = new Button(this);
button.setId(i); //・・・(7)
button.setHeight(getCellHeight()); //・・・(8)
button.setWidth(getCellWidth()); //・・・(9)
//ボタンに裏面の画像をセット
button.setBackgroundDrawable(
getResources().getDrawable(R.drawable.card_back)
);
setEvent(button); //・・・(10)
tableRow.addView(button);
}
return tableLayout;
}
/**
* 行数と画面の幅からセルの高さを算出
* @return セルの高さ
*/
private int getCellHeight() {
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
return display.getHeight() / ROW;
}
/**
* 列数と画面の幅からセルの幅を算出
* @return セルの幅
*/
private int getCellWidth() {
WindowManager windowManager = getWindowManager();
Display display = windowManager.getDefaultDisplay();
return display.getWidth() / COL;
}
/**
* 各ボタンビューにイベントをセット
* @param button
*/
private void setEvent(Button button) {
//タップ時の動作
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button button = (Button)v;
int cardId = button.getId();
button.setBackgroundDrawable(
card[cardId].getCardImg()
);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_android_test, menu);
return true;
}
}
/**
* カードのクラス
*/
class Card {
private int imgNo; //画像番号
private Drawable cardImg; //画像
Card(int imgNo, Drawable cardImg) {
this.imgNo = imgNo;
this.cardImg = cardImg;
}
int getImgNo() {
return imgNo;
}
Drawable getCardImg() {
return cardImg;
}
}
たった、これだけ。
各ボタンビューにイベントをセットしている部分だけれども、どう変更したか見てみよう。
/**
* 各ボタンビューにイベントをセット
* @param button
*/
private void setEvent(Button button) {
//タップ時の動作
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button button = (Button)v;
button.setBackgroundDrawable(
getResources().getDrawable(R.drawable.card_open)
);
}
});
}
これが、
/**
* 各ボタンビューにイベントをセット
* @param button
*/
private void setEvent(Button button) {
//タップ時の動作
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Button button = (Button)v;
int cardId = button.getId();
button.setBackgroundDrawable(
card[cardId].getCardImg()
);
}
});
}
こうなったってわけ。
これまで固定で星マーク(card_open.png)の画像を表示していた部分を、cardクラスのインスタンスを使った配列からの画像を表示するようにしただけだ。
つまり、まずは
int cardId = button.getId();
として新たに変数「cardId」を定義して、これに「getID」メソッドを使ってタップされたボタンのIDを取得する。
次に、
card[cardId]
として、そのボタンにセットされたcardクラスのインスタンスを使った配列を取得する。
この配列は、前述の説明のとおりだね。
最後に、
card[cardId].getCardImg()
として、cardクラスのゲッターとして定義した「getCardImg」メソッドを使って、セットしたカード画像を取得している。
念のため、「getCardImg()」の定義は以下のとおり。
Drawable getCardImg() {
return cardImg;
}
return値として、カード画像を返してるだけだ。
これで、タップされたボタンにセットされたカード画像が表示されるって仕掛け。
簡単だね。
ではできたプログラムをAVDで実行して、実際にカードをタップ(クリック)してみよう。
ホラ、12組24枚のカード画像がランダムにセットされていることが確認できたでしょ。
というところで、今回は終了。
さてAVDで実行してみたところで気づいたと思うけれども、今のプログラムじゃ表にしたカードを裏に戻すことができないよね。
というわけで、次回はカードを裏返す仕組みを追加するところから初めてみようかな・・・乞うご期待。