Android Market公開を目指してAndroidアプリを開発する!(翻訳履歴保存編)では、翻訳結果をSQLiteに保存するようにしたので、今回は、その結果を参照する機能を実装していきたいと思います。
データベースは前回のサンプルで作成したものを利用します。
今回のサンプルは、ArrayAdapterとListViewコントロールを使って、翻訳履歴を一覧表示するだけという単純なのものにしました。
まず、前回作ったData Access Object(DAO)に、翻訳履歴を取得する処理を追加します。
1 2 3 4 5 6 | public Cursor find(String[] columns, String order, String limit) { SQLiteDatabase db = connection.getWritableDatabase(); Cursor cursor = db.query( false , ITranslate.TABLE_NAME, columns, null , null , null , null , order, limit); return cursor; } |
次に、翻訳結果の情報を格納しているTranslateModelクラスにtoString()関数をオーバーライドします。
1 2 3 4 | @Override public String toString() { return translated; } |
後は、SQLiteから取得した翻訳結果をArrayAdapterクラスに格納して、それをListViewコントロールにセットします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package jp.flashcast.translator.android; import jp.flashcast.translator.android.dao.TranslateDao; import jp.flashcast.translator.android.model.TranslateModel; import android.app.Activity; import android.database.Cursor; import android.os.Bundle; import android.provider.BaseColumns; import android.widget.ArrayAdapter; import android.widget.ListView; public class TranslatorSample5 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main); TranslateDao dao = new TranslateDao( this ); ArrayAdapter<TranslateModel> adapter = new ArrayAdapter<TranslateModel>( this , android.R.layout.simple_list_item_1); addTranslateModel(adapter, dao.find( null , BaseColumns._ID + " DESC" , null )); ListView view = (ListView)findViewById(R.id.histories); view.setAdapter(adapter); } private void addTranslateModel(ArrayAdapter<TranslateModel> adapter, Cursor cursor) { if (cursor != null ) { if (cursor.getCount() > 0 ) { while (cursor.moveToNext()) { TranslateModel model = new TranslateModel(); model.setId(cursor.getInt( 0 )); model.setOriginal(cursor.getString( 1 )); model.setTranslated(cursor.getString( 2 )); model.setSrcLanguage(cursor.getString( 3 )); model.setDstLanguage(cursor.getString( 4 )); model.setDt(cursor.getString( 5 )); adapter.add(model); } } } } } |
TranslateModelクラスにtoString()関数をオーバーライドしたことで、翻訳結果だけが一覧に表示されるようになります。
画面レイアウトのXMLはこんな感じです。
1 2 3 4 5 6 7 8 9 10 11 12 | <? xml version = "1.0" encoding = "utf-8" ?> android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < ListView android:id = "@+id/histories" android:layout_width = "fill_parent" android:layout_height = "wrap_content" /> </ LinearLayout > |
実行結果はこちら。
あまりにシンプルすぎるので、もうちょっと工夫したいと思います。
- ListViewの1行に翻訳前と翻訳後、翻訳した時間を表示し、削除ボタンもつける。
- 件数が増えてくると画面が長くなりすぎるので、一覧の下に「もっと読む」みたいな機能をつけて、はじめは特定の件数だけ表示する。
では、これを実現するにはどうするか?
ArrayAdapterの親クラスであるBaseAdapterを継承したクラスと、ListViewクラスを継承したクラスを実装して実現します。
前者については、こちらが非常に参考になりました。
ListViewを拡張する方法 | public static void main
まず、1行のレイアウトにあたるXMLを用意します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | <? xml version = "1.0" encoding = "utf-8" ?> < LinearLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" > < LinearLayout android:orientation = "vertical" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_weight = "1" > < TextView android:id = "@+id/original" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:layout_gravity = "left" android:layout_marginLeft = "10sp" android:singleLine = "true" android:textSize = "15sp" android:textStyle = "bold" /> < TextView android:id = "@+id/translated" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:layout_gravity = "left" android:layout_marginLeft = "10sp" android:singleLine = "true" android:textSize = "12sp" /> < RelativeLayout android:layout_width = "wrap_content" android:layout_height = "wrap_content" > < TextView android:id = "@+id/dt" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_alignParentRight = "true" android:layout_marginRight = "10sp" android:textSize = "12sp" /> </ RelativeLayout > </ LinearLayout > < ImageView android:id = "@+id/delete" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:layout_gravity = "center_vertical|center_horizontal" android:layout_marginRight = "5sp" /> </ LinearLayout > |
次に、ArrayAdapterの親クラスであるBaseAdapterを継承したクラスを作ります。1行のレイアウトはgetView()関数の中で設定(42行目)します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | package jp.flashcast.translator.android.adapter; import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.View.OnClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.TextView; import jp.flashcast.translator.android.R; import jp.flashcast.translator.android.manager.HistoryManager; import jp.flashcast.translator.android.model.TranslateModel; import jp.flashcast.translator.android.view.TranslateListView; public class TranslateAdapter extends BaseAdapter { private LayoutInflater inflater; private ArrayList<TranslateModel> list; private HistoryManager manager; public TranslateAdapter(Context context, ArrayList<TranslateModel> list, HistoryManager manager) { this .list = list; this .manager = manager; this .inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } public int getCount() { return list.size(); } public Object getItem( int position) { return list.get(position); } public long getItemId( int position) { return list.get(position).getId(); } public View getView( int position, View convertView, ViewGroup parent) { convertView = inflater.inflate(R.layout.list_item, null ); TextView original = (TextView)convertView.findViewById(R.id.original); TextView translated = (TextView)convertView.findViewById(R.id.translated); TextView dt = (TextView)convertView.findViewById(R.id.dt); ImageView image = (ImageView)convertView.findViewById(R.id.delete); original.setText(list.get(position).getOriginal()); translated.setText(list.get(position).getTranslated()); dt.setText(list.get(position).getDt()); image.setImageResource(android.R.drawable.ic_menu_delete); image.setId(list.get(position).getId()); image.setOnClickListener( new OnClickListener() { public void onClick(View v) { manager.delete(v.getId()); int max = manager.getHistoriesCount(); int len = manager.setTranslateAdapter(TranslateAdapter. this , true ); int pos = HistoryManager.HISTORY_LIST_VIEW_COUNT * (manager.getPage() - 1 ); TranslateListView view = ((TranslateListView)v.getParent().getParent()); view.setAdapter(TranslateAdapter. this ); view.setFooterVisible(!(len == max)); view.setSelection((max > pos) ? pos : max); } }); return convertView; } public void add(TranslateModel model) { list.add(model); } public void clear() { list.clear(); } } |
55~68行目が削除ボタンクリック時の処理になります。
続いて、後者のほうです。
件数が増えてくると画面が長くなりすぎるので、一覧の下に「もっと読む」みたいな機能をつけて、はじめは特定の件数だけ表示する。
こちらのサイトが非常に参考になりました。
tappli blog: [Android] ListViewとFooterView
サンプルソースがダウンロードできるのはとてもありがたいです!
ListViewを継承したクラスを作ります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package jp.flashcast.translator.android.view; import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.widget.ImageView; import android.widget.ListView; import jp.flashcast.translator.android.R; public class TranslateListView extends ListView { private View footer; private boolean visible; public TranslateListView(Context context, AttributeSet attrs) { super (context, attrs); } @Override public void addFooterView(View footer) { super .addFooterView(footer); if ( this .footer != null ) { removeFooterView( this .footer); } this .footer = footer; ImageView img = (ImageView) this .footer.findViewById(R.id.more); img.setImageResource(android.R.drawable.ic_menu_more); } public void setFooterVisible( boolean visible) { if ( this .footer != null ) { if (!visible) { removeFooterView( this .footer); } } this .visible = visible; } public boolean isFooterVisible() { return this .visible; } } |
実行結果はこちら。
●初期表示
※ ここでは、翻訳履歴が少なくてもいいように、2件づつ表示されるようににしています。
●一覧の一番下の行(もっと読むのような)を押した後
●削除ボタンを押して履歴をすべて削除した後
さっきよりも、使い勝手も良くなったのではないかと思います!