Androidでこのレイアウトを実現したい
この問題には丸一日費やしても解決できませんでした。。。。
レイアウト関係に詳しい方お願いします。
背景の変な模様が↓xmlで言うなら背景として row_bg が設定されているルートのLLです。
(実際はルートではないですがこのサンプルxml内でのルート)
↑半透明のグレーが↓xmlで言うなら contentArea のidのビュー
その中の白文字の「ああああ」が message のidのビュー
↑nameから始まっているのが↓でのnameのidがついているビュー
timeも同様です。
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/row_bg"
android:orientation="vertical">
<LinearLayout
android:id="@+id/infoArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"/>
<TextView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="right"/>
</LinearLayout>
<LinearLayout
android:id="@+id/contentArea"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/row_content_bg"
android:orientation="vertical">
<TextView
android:id="@+id/message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"/>
</LinearLayout>
</LinearLayout>
contentArea 内は今回説明に不要なので一つだけビューを残して省略しているので LinearLayout になっています。
TextView 1つだけしか入っていないのと同じように考えてもらっても同じ動作になるので1つしかないと考えてもらっても結構です。
やりたいことは、単純に
contentArea の minWidth に infoArea の width を指定して、
infoArea の minWidth に contentArea の width を指定した感じのレイアウトにしたいです。
contentArea と contentArea はまず、お互い wrap_content でサイズを決定後、横幅を横幅の大きい方に合わせるという感じになります。
なので上記のように minWidth でお互いの wrap_content の横幅を指定できればベストです。
ただ、このコードのままでは実現できていませんが、 time は親ビューの右端にくっつけたいです。
name に width=0dp & weight=1 を指定した感じです。
name が 親の余った横幅を埋めるので time は自然と親ビューの右にくっつきます。
ビューの背景の関係でどうしてもこのようにしなければなりません。
このxmlでのルートビューは実際はルートではなく、親のコンテンツエリアが許す限りコンテンツに合わせて横幅が可変していきます。
説明その2(↑でやりたいことが理解できた方は読まなくても大丈夫です)
このxmlでのルートビューは 吹き出し全体 になります。
drawable/row_bg は吹き出しの形をしていると考えてもらえるといいかと思います。
そして、吹き出しの中は2行で構成されています。
1行めは 名前、時間
2行めは メッセージ本文です。
メッセージ本文にも背景指定があります。
時間は吹き出しの右にくっつけます
時間の親ビューの横幅が時間の親の親の横幅を埋め尽くすとして、時間は親ビューの右端にくっつける感じです。
(説明下手で難しく感じるかもしれないですが、要するにただ単に吹き出し全体のできるだけ右に位置します)
1行めと2行めはそれぞれコンテンツサイズを計算し、
計算後、お互いの行とくらべて横幅が小さい方は大きい方にサイズを変更します。
そうすることで、
・1行めは最低でも自分のコンテンツ領域を確保しつつ、2行めより小さかったら2行めの横幅になり、時間を右にくっつくける事ができる
・メッセージは最低でも自分のコンテンツ幅を確保しつつ、1行めより小さかったら1行めの横幅になり、メッセージの背景が横いっぱいに表示される。
ただ、メッセージの自分のコンテンツ幅を確保とは親が許す限りいくらでも横に大きく可変できる。
なので、メッセージの横幅が無限大だとしたらこのxmlでのルートビューの親ビューのコンテンツエリアサイズになるということです。
(難しいことではなく、普通にアンドロイドのレイアウト機能に備わっている機能です
テキストビューにwrap_contentを指定した場合、親が許す限りの横幅で、限界まで来たら勝手に改行されるという普通の機能)
ここから下は私の失敗Reportなので読まなくても大丈夫です。
試したのは LinearLayout, TableLayout, GridLayout です。
これらの中で一番目的の見た目(minWidthを設定したような動作)になったのは、 GridLayout ですが、おそらく一番今回使用 で・き・な・い レイアウトになります。
なぜなら、セル単位での背景指定がないため、セルのを伸ばした時、伸ばされた部分がセルの背景ではなく GridLayout 全体で指定する背景になってしまうからです。
レイアウトの記述が変わり、背景リソースの設定箇所も変わるので説明しにくいのですが、不可能だと思われます。
できるとすれば、 cell の要素を最初は wrap_content にして、すべての cell サイズが確定後、 cell のコンテンツを match_parent にして cell いっぱいに引き延ばすことですが、できるか分かりません。
GridLayout はこれもレイアウトの記述が変わり説明しにくいのですが、
下の行である message は上の行である infoArea の横幅に従って横幅を決めるため、messageの横幅の最大値がinfoAreaの横幅になってしまうので無理でした。
(このxmlでのルートビューの親ビューが許す限り可変にしたいので)
あと OnGlobalLayoutListener 内部でそれぞれに minWidth を設定する方法も試しましたがそもそもここでレイアウトサイズを変更すべきではないでしょうし、呼ばれるタイミングが描画後なのと問題がたくさんあってだめでした。