ListViewのEmptyViewが使えないので代替案を考える

ListViewは便利なんだけど表題の通りEmptyViewが使いものにならない。

普通の使い方

普通にListViewのEmptyViewを使おうとするとこんな感じになると思う。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

    <ListView
            android:id="@+id/list_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

    <LinearLayout
            android:id="@+id/empty_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

        <!-- EmptyViewの中身 -->

    </LinearLayout>

</FrameLayout>

このレイアウトでコードはこんな感じ

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);
        
        ListView listView = (ListView) findViewById(R.id.list_view);
        LinearLayout emptyView = (LinearLayout) findViewById(R.id.empty_view);
        
        listView.setEmptyView(emptyView);
        
        // その後の処理
    }

これでListViewに設定しているAdapterが0件かどうかでEmtpyViewをVisible or Goneへと制御してくれる。0件表示も簡単にできると喜び勇みたいところだけど実はそうじゃない。以下の問題点がある。

  • Adapterの件数が0件の場合は容赦なく0件表示が表示される。EmptyViewだからそうなんだろうけど、リロードしたりして一瞬でも0件になるとEmptyViewがチラ見えしてしまう。
  • ヘッダー、フッターも消えてしまう。ListViewとEmptyViewを入れ替えているだけなのでヘッダー、フッターが設定していようがしていなかろうが容赦なく消えてしまう。

詳しくはやんざむ先生が書いてるんでそっちを見るといいと思う。

理屈はわかったんだけど、ヘッダーを表示して0件表示したいってことは結構ある。やんざむ先生が言われてる方法もできるんだけど、これだとViewは出来上がるけど別のインスタンスなのでイベントの設定とかが非常に煩わしい。なので無理やり設定してしまおうというのが今回の趣旨。具体的にはこんな感じ。

    private View mEmptyView;

    /**
     * 0件表示の表示する
     */
    public void showEmptyView(View emptyView) {
        if (emptyView != null && isEmpty()) {
            // 渡された0件表示を無理やり表示するために適当な値を作成
            mEmptyView = emptyView;
            add((T) new Object());
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        // 0件表示
        if (mEmptyView != null) {
            return mEmptyView;
        }

        return super.getView(position, convertView, parent);
    }

getViewをOverrideしてカスタムビューを返答するというのはよくあると思うんだけど、ここをちょこっと弄くっとEmptyViewが設定されてたらそれを返答してしまうことでListViewの列としてEmptyViewを表示してしまおうという考え方。これだとヘッダーも表示できるし、ListViewの中にEmptyViewが表示できるしで結構良い。問題としてはListViewに追加してるからonItemClickが走ってしまって変な値がとれる場合を考えないといけないってぐらいかと思う。今のところそこまで問題は起こっていない。mEmptyViewの初期化さえ間違えなければちゃんと動くはず。

まとめ

EmptyViewの問題は色々調べてみたんだけど結構根深そうで、あっちをたてればこっちがたたずと非常に悩ましい。ヘッダー、フッターを表示したままEmptyが表示できるとか、Emptyだけじゃなくて初期表示を弄くれるとかそこらへんまで充実してくれるとありがたいなー