Android SlidingDrawerでwrap_contentを効かせつつ表示/非表示での高さを切り替える

2011/05/04
2021/02/25

他の部品を隠さずにSlidingDrawerを使い、コンテンツの大きさに合わせてSlidingDrawerをレイアウトする方法についてです。この説明もタイトルも、一言でうまく伝えられないので、まずは完成イメージをまず載せます。

ソースコードは改めて投稿します。

完成イメージ

1. 画面の下方にスクロールする部品があります。(TextView)

2. ドロワーを開くと、スクロールするビューのスクロールバーがずれています。つまり、ドロワーで隠れてしまった部分を下方にスクロールすることで表示できます。

3. 実際、最下部までスクロールできます。(「終わり」という部分です。)

4. ドロワーを閉じると、スクロールビューが元のサイズに戻ります。

一見するとごく普通の動きで、Gmailのアプリでもメールのチェックボックスにチェックをつけるとドロワーが現れ、同様の動きをします。

Gmailやspモードメールのアプリの動作を見て、これはSlidingDrawerを使っているのだろう、とあたりをつけた所までは良かったのですが、これを実現するのにかなり苦労してしまいました。

問題1

まずSlidingDrawerをよくあるサンプルの通りに作成し、SlidingDrawerのサイズをコンテンツ(上記でいうダミーボタン)のサイズに合わせるためにandroid:layout_height="wrap_content"を指定します。

1. ドロワーが閉じているにもかかわらず、スクロールビューが非表示になっています。(ドロワーが画面一杯に広がってしまっています。)

2. ドロワーを開くと、画面一杯にドロワーが開いてしまいます。

問題2

wrap_contentが効かないので、固定値で100dpと指定してみます。

1. ドロワーを開くと、とりあえずはうまくいっているように見えます。ただ、SlidingDrawerに含めるコンテンツに合わせて100dpの値を調整することになるのであまり良いやり方ではありません。

2. しかも、ドロワーが閉じていても100dp分の空きスペースができてしまいます。

問題3

stackoverflowのQ&Aに、wrap_contentを有効にする方法がありました。

SlidingDrawerのラッパーを使い、wrap_contentが有効になるようにonMeasure()をオーバーライドする、ということのようです。

Android: can height of SlidingDrawer be set with wrap_content? - stackoverflow

1. このラッパーを使うことでwrap_contentが効きました。調度よいサイズでドロワーがレイアウトされているようです。

2. しかし、やはりドロワーが閉じている状態では空きスペースができてしまいます。

問題4

ドロワーが閉じている時は、ウィジェットのサイズを0にするように修正してみます。

1. ドロワーが閉じているときにスクロールビューがきちんと表示されました。

2. ドロワーを開くと、スクロールビューがレイアウト調整されて、隠れた部分がスクロールできるようになっているのがスクロールバーの位置からわかります。

3. 実際に隠れた部分を表示できました。これでやっと完成、と思いましたが…

4. ドロワーを閉じると空きスペースができてしまいます…

Android SDKのソースコードもざっと見てみましたが、どうやらドロワーが閉じたときは再レイアウトされないようです。ドロワーを閉じたとき(onDrawerClosed())にrequestLayout()を呼ぶようにしたところ、最初の完成イメージのようになりました。

別の問題

RelativeLayoutで、スクロールビューがドロワーの位置をandroid:layout_aboveで指定しているために上記のような問題が起こります。これを外すと、スクロールビューのレイアウトはドロワーのレイアウトの影響を受けなくなります。

1. ドロワーが閉じているときに空きスペースができてしまうようなことはありません。

2. その代わり、ドロワーが表示されるとドロワーで隠れた部分を見ることができなくなります。

© 2010 ksoichiro