再び単位換算アプリを作ってみる

単位換算アプリを作る - fukuitの日記の続き。例のネコにならって、AppInventorを使ってみる - fukuitの日記で作りかけた、身長と体重をりんごの個数に換算するアプリを作ってみる。
今回、チャレンジするのは、ListViewの扱い。sqldbに保存したデータをListViewでアレコレするsampleはNotePad tutorialに有るんだけれど、ちょっとアレって盛りだくさんな感じがして、オレの理解が追いつかない。
そういうワケで、入力されたデータは永続化されないけれど、まあサンプルですから。お勉強ですから。

layout/main.xml

身長と体重を入力するEditTextは上下に並べて、実行するボタンはその横に並べて、さらに、その下にListViewを配置したい。だから、LinearLayoutを多重に配置してみた。やり方としてこれで良いのかどうかは不明。だいたい、こんな感じ。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<LinearLayout android:id="@+id/LinearLayout04"
		android:layout_width="fill_parent" android:layout_height="wrap_content"
		android:orientation="horizontal">
		<LinearLayout android:id="@+id/LinearLayout03"
			android:layout_width="wrap_content" android:layout_height="wrap_content"
			android:orientation="vertical">
			<LinearLayout android:id="@+id/LinearLayout01"
				android:layout_width="fill_parent" android:layout_height="wrap_content"
				android:orientation="horizontal">
				<TextView android:text="@string/height" android:id="@+id/TextView01"
					android:layout_width="wrap_content" android:layout_height="wrap_content"
					android:typeface="monospace" />
				<EditText android:text="@string/height_init" android:id="@+id/height"
					android:layout_width="@dimen/inputAreaWidth" android:layout_height="wrap_content"
					android:typeface="monospace" android:inputType="number" />
				<TextView android:text="@string/height_unit" android:id="@+id/TextView03"
					android:layout_width="wrap_content" android:layout_height="wrap_content"
					android:typeface="monospace" />
			</LinearLayout>
			<LinearLayout android:id="@+id/LinearLayout02"
				android:layout_width="fill_parent" android:layout_height="wrap_content"
				android:orientation="horizontal">
				<TextView android:text="@string/weight" android:id="@+id/TextView02"
					android:layout_width="wrap_content" android:layout_height="wrap_content"
					android:typeface="monospace" />
				<EditText android:text="@string/weight_init" android:id="@+id/weight"
					android:layout_width="@dimen/inputAreaWidth" android:layout_height="wrap_content"
					android:typeface="monospace" android:inputType="number" />
				<TextView android:text="@string/weight_unit" android:id="@+id/TextView04"
					android:layout_width="wrap_content" android:layout_height="wrap_content"
					android:typeface="monospace" />
			</LinearLayout>
		</LinearLayout>
		<Button android:text="@string/btn" android:id="@+id/exec_btn"
			android:layout_width="fill_parent" android:layout_height="fill_parent" />
	</LinearLayout>
	<ListView android:id="@android:id/list" android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:scrollbars="vertical"
		android:scrollbarStyle="outsideInset" android:smoothScrollbar="true" />
	<TextView android:id="@android:id/empty" android:text="@string/no_list"
		android:layout_width="fill_parent" android:layout_height="wrap_content" />
</LinearLayout>

を設定したので、ListViewに設定するListが空リストの時は「No Data」とかって表示する。

values/strings.xmlとvalues/dimens.xml

ということで、layout.xmlの中で呼んでいるリソースを以下のように。

<?xml version="1.0" encoding="utf-8"?>
<resources>
	<string name="hello">Hello World, KittyCounter!</string>
	<string name="app_name">KittyCounter</string>
	<string name="btn">換算</string>
	<string name="height">身長</string>
	<string name="weight">体重</string>
	<string name="height_unit">cm</string>
	<string name="weight_unit">kg</string>
	<string name="height_init">180</string>
	<string name="weight_init">75</string>
	<string name="no_list">No Data.</string>
	<string name="menu_delete">削除</string>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
	<dimen name="inputAreaWidth">160sp</dimen>
</resources>

こうやってxmlファイルとはいえ、日本語埋め込みだったりとか決め打ちで160spとか書いちゃってるのは気持ち悪いけど、お勉強だからいいのだ。

KittyItem.java

このclass名には問題がある気もするけれど、ソレはサテオクとして、身長と体重を保持するclassを作っておく。setterで入力された身長・体重をりんごの個数に変換しておくようにする。

package com.example.kitty;
public class KittyItem {
	private final double apple_weight=0.300;
	private final double apple_height=10.0;
	private double weight;
	private double height;
	private int convertedWeight;
	private int convertedHeight;
	public double getWeight() {
		return weight;
	}
	public void setWeight(double weight) {
		this.weight = weight;
		this.convertedWeight = (int)(weight/this.apple_weight);
	}
	public double getHeight() {
		return height;
	}
	public void setHeight(double height) {
		this.height = height;
		this.convertedHeight = (int)(height/this.apple_height);
	}
	public KittyItem(double weight, double height) {
		super();
		this.weight = weight;
		this.height = height;
		this.convertedWeight = (int)(weight/this.apple_weight);
		this.convertedHeight = (int)(height/this.apple_height); 
	}
	public KittyItem() {
		super();
		this.weight = 0.0;
		this.height = 0.0;
		this.convertedWeight=0;
		this.convertedHeight=0;
	}	
	public String toString(){
		StringBuilder sb = new StringBuilder();
		sb.append("身長: りんご").append(this.convertedHeight).append("個分 / 体重: りんご").append(this.convertedWeight).append("個分");
		return sb.toString();
	}
}

また、日本語埋め込みだけど(以下略)。

KittyCounter.java

まず、ListViewを楽して使うために、メインのactivityをListActivityを継承することにする。
で、ArrayAdapterのadapterを作成して、setListAdapter()する。adapterに追加するのは、KittyItem型だ。
KittyItemにはtoString()で、身長・体重をりんごの個数で表すようにしてあるから、ListViewのItemをclickしたら実際の身長・体重をToastで表示するようにしてみた。あとは、ContextMenuで削除するようにもしてみた。

package com.example.kitty;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;

public class KittyCounter extends ListActivity {
	private ArrayAdapter<KittyItem> adapter;
	private static final int DELETE_ID = Menu.FIRST + 1;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		adapter = new ArrayAdapter<KittyItem>(this,
				android.R.layout.simple_list_item_1);
		setListAdapter(adapter);

		final Button btn = (Button) findViewById(R.id.exec_btn);
		btn.setOnClickListener(new View.OnClickListener() {
			@Override
			public void onClick(View v) {
				doCalculate();
			}
		});
		registerForContextMenu(getListView());
	}

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
		KittyItem item = (KittyItem)l.getAdapter().getItem(position);
		StringBuilder sb = new StringBuilder();
		sb.append("身長:").append(item.getHeight()).append("cm / 体重:")
				.append(item.getWeight()).append("kg");
		Toast.makeText(this, sb.toString(), Toast.LENGTH_LONG).show();
	}

	@Override
	public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
		super.onCreateContextMenu(menu, v, menuInfo);
		menu.add(0, DELETE_ID, 0, R.string.menu_delete);
	}

	@Override
	public boolean onContextItemSelected(MenuItem item) {
		switch(item.getItemId()) {
		case DELETE_ID:
			AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
			KittyItem kitty = (KittyItem)getListView().getAdapter().getItem(info.position);
			adapter.remove(kitty);
			return true;
		}
		return super.onContextItemSelected(item);
	}
    
	private void doCalculate() {
		EditText hEdit = (EditText) findViewById(R.id.height);
		EditText wEdit = (EditText) findViewById(R.id.weight);
		double h = Double.parseDouble(hEdit.getText().toString());
		double w = Double.parseDouble(wEdit.getText().toString());
		adapter.add(new KittyItem(w, h));
	}
}


ということで、ひとまず、エミュレータ上で動くことは確認した。ListViewって、android.R.layout.simple_list_item_1で使う分には、簡単だな。