24370


この問題には丸一日費やしても解決できませんでした。。。。  
レイアウト関係に詳しい方お願いします。

[![画像の説明をここに入力](https://i.stack.imgur.com/lnao4.png)](https://i.stack.imgur.com/lnao4.png)  
背景の変な模様が↓xmlで言うなら背景として row_bg が設定されているルートのLLです。  
（実際はルートではないですがこのサンプルxml内でのルート）

↑半透明のグレーが↓xmlで言うなら contentArea のidのビュー  
その中の白文字の「ああああ」が message のidのビュー

↑nameから始まっているのが↓でのnameのidがついているビュー  
timeも同様です。

[code]

    <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>
    
[/code]

contentArea 内は今回説明に不要なので一つだけビューを残して省略しているので LinearLayout になっています。  
TextView １つだけしか入っていないのと同じように考えてもらっても同じ動作になるので１つしかないと考えてもらっても結構です。

やりたいことは、単純に  
contentArea の minWidth に infoArea の width を指定して、  
infoArea の minWidth に contentArea の width を指定した感じのレイアウトにしたいです。  
contentArea と contentArea はまず、お互い wrap_content
でサイズを決定後、横幅を横幅の大きい方に合わせるという感じになります。  
なので上記のように minWidth でお互いの wrap_content の横幅を指定できればベストです。

ただ、このコードのままでは実現できていませんが、 time は親ビューの右端にくっつけたいです。  
name に width=0dp & weight=1 を指定した感じです。  
name が 親の余った横幅を埋めるので time は自然と親ビューの右にくっつきます。

ビューの背景の関係でどうしてもこのようにしなければなりません。  
このxmlでのルートビューは実際はルートではなく、親のコンテンツエリアが許す限りコンテンツに合わせて横幅が可変していきます。

## 説明その２（↑でやりたいことが理解できた方は読まなくても大丈夫です）

このxmlでのルートビューは 吹き出し全体 になります。  
drawable/row_bg は吹き出しの形をしていると考えてもらえるといいかと思います。

そして、吹き出しの中は２行で構成されています。  
１行めは 名前、時間  
２行めは メッセージ本文です。

メッセージ本文にも背景指定があります。

時間は吹き出しの右にくっつけます  
時間の親ビューの横幅が時間の親の親の横幅を埋め尽くすとして、時間は親ビューの右端にくっつける感じです。  
（説明下手で難しく感じるかもしれないですが、要するにただ単に吹き出し全体のできるだけ右に位置します）

１行めと２行めはそれぞれコンテンツサイズを計算し、  
計算後、お互いの行とくらべて横幅が小さい方は大きい方にサイズを変更します。  
そうすることで、  
・１行めは最低でも自分のコンテンツ領域を確保しつつ、２行めより小さかったら２行めの横幅になり、時間を右にくっつくける事ができる  
・メッセージは最低でも自分のコンテンツ幅を確保しつつ、１行めより小さかったら１行めの横幅になり、メッセージの背景が横いっぱいに表示される。  
ただ、メッセージの自分のコンテンツ幅を確保とは親が許す限りいくらでも横に大きく可変できる。  
なので、メッセージの横幅が無限大だとしたらこの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
を設定する方法も試しましたがそもそもここでレイアウトサイズを変更すべきではないでしょうし、呼ばれるタイミングが描画後なのと問題がたくさんあってだめでした。


CC BY-SA 3.0
2016-04-25T03:06:54.513
24323
2016-04-26T16:13:33.923
2016-04-26T05:38:39.667
10346
10346
question
android
Androidでこのレイアウトを実現したい


ふむふむ。。パズルのようでなかなか面白い問題ですね。

XMLだけで実現するのは無理そうなのでカスタムViewを作ってみました。

[code]

    public class MaxLinearLayout extends LinearLayout {
    
        // コンストラクタ...（省略）
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // 全ての子要素の幅を計算
            int maxWidth = 0;
            for (int i=0; i<getChildCount(); ++i) {
                View child = getChildAt(i);
                child.measure(
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
                        MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
                );
                maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
            }
    
            // 最大値をこのビューの幅として設定する
            widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.getMode(widthMeasureSpec));
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }
    
[/code]

XML内では以下のように使用してください。  
（com.exampleの部分はパッケージ名に置き換えてください）

[code]

    <com.example.MaxLinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical">
    
        <LinearLayout
            android:id="@+id/infoArea"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <TextView
                android:id="@+id/name"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
    
            <Space
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_weight="1"/>
    
            <TextView
                android:id="@+id/time"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
    
        </LinearLayout>
    
        <LinearLayout
            android:id="@+id/contentArea"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
    
            <TextView
                android:id="@+id/message"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
    
        </LinearLayout>
    
    </com.example.MaxLinearLayout>
    
[/code]

レイアウトエディタのプレビューで確認した限りではこれで要件を満たしているように思いますがいかがでしょうか？


CC BY-SA 3.0
2016-04-26T15:49:17.280
24370
2016-04-26T16:13:33.923
2016-04-26T16:13:33.923
915
915
24323
answer