Android Binding 〜SDカードファイルビュー〜
昨日の続きです。今日は以下のことをやろうと思います。
- リストをソートして表示
- ファイルを選択したらIntentを投げてアプリ起動
- 現在のパスをタイトルバーに表示
サンデープログラミングなのでかなりヌルイ目標設定になっています (汗) 。一つずつ対応していきましょう。
まずもっとも簡単なソートです。これはViewModelクラス内でFile配列をDirectoryEntryクラスの配列に変換してArrayListObservableオブジェクトに設定しているところがあるのでここでソートしてしまいます。
◆ViewModelクラス
public void setPath(String path) { // ... 省略 ... // エントリ列を昇順にソートする (ココ!) Arrays.sort(entries, _entryComparator); // リスト表示を更新する DirectoryEntryList.setArray(entries); } // ディレクトリエントリ列ソート用比較オブジェクト private final Comparator<DirectoryEntry> _entryComparator = new Comparator<TestExplorerViewModel.DirectoryEntry>() { @Override public int compare(DirectoryEntry entry1, DirectoryEntry entry2) { // まずはディレクトリを優先する boolean isFile1 = entry1.IsFile.get(); boolean isFile2 = entry2.IsFile.get(); if(!isFile1 && isFile2) return -1; if(isFile1 && !isFile2) return 1; // それでも決着が付かない場合は名前順とする return entry1.Name.get().compareTo(entry2.Name.get()); } };
ソートは次のような法則で行っています。
ディレクトリとファイルを分けるとリストの見通しが若干よくなります。
次にファイルをタップしたらIntentを投げるようにしてみます。これでグッとエクスプローラ風に見えるようになります。こちらはリストクリックアクションにバインドされたコマンドを変更します。
◆ViewModelクラス
public Command OnItemClicked = new Command() { @Override public void Invoke(View view, Object... args) { // ... 省略 ... // ファイルをタップしたらIntent起動する if(clicked.IsFile.get() == true) { sendIntent(_currentPath + "/" + clicked.Name.get()); return; } // ... 省略 ... } } private void sendIntent(String path) { // 暗黙Intentのためのパラメータを準備する File file = new File(path); Uri uri = Uri.fromFile(file); String mime = MimeUtils.getMimeType(file.getName()); // Intentオブジェクトを初期化する Intent intent = new Intent(); intent.setAction(Intent.ACTION_VIEW); intent.setDataAndType(uri, mime); // 暗黙Intentを発行する try { context.startActivity(intent); } catch(ActivityNotFoundException e) { Toast.makeText( _context, _context.getText(R.string.application_not_found), Toast.LENGTH_LONG).show(); } }
ここで注意が必要なのはIntentを発行したり、トーストメッセージを表示する時、Contextオブジェクトが必要だということです。こればっかりは外から (Activityから) もらわないとイケません。なので、ViewModelクラスのコンストラクタでもらうことにしました。
◆ViewModelクラス
private Context _context = null; public TestExplorerViewModel(Context context) { _context = context; }
最後の目標も片付けてしまいましょう。タイトルバーに現在のパスを表示します。
・・・と思い、頑張ってタイトルバーをカスタマイズしてパスを表示しようとしましたが、どうもタイトルバーからはバインド出来ないようです。
なので、タイトルを消して、ListViewの (固定) ヘッダを追加して、タイトルバーっぽく見せるようにしました。仕事でもそうだったんですが、タイトルバーのカスタマイズって何かとうまくいかない (ように感じます) 。
タイトルと現在パスをバインドするのはとっても簡単。
◆レイアウト定義
<!-- ... 省略 ... --> <TextView ... 省略 ... binding:text="CurrentPath" />
◆ViewModelクラス
// 現在パスプロパティ // これまで_currentPathに設定していたのをこちらに設定するようにする public StringObservable CurrentPath = new StringObservable("");
これで終了です。この辺りの簡潔さがAndroid bindingらしいところですね。
これらの他にちょっと見た目を凝ってみました。アイコンがいまいちなのはご勘弁。
いつものようにソースコードはこちらです。ご参考ください。