ListViewは実際には、すべてのアイテムを表示するのに十分な高さになるようにそれ自体を測定することができますが、単にwrap_content(MeasureSpec.UNSPECIFIED)を指定しただけでは測定できません。MeasureSpec.AT_MOSTで高さを指定すると、これが行われます。この知識があれば、非常に単純なサブクラスを作成してこの問題を解決できます。この問題は、上記のどのソリューションよりもはるかにうまく機能します。このサブクラスでは引き続きwrap_contentを使用する必要があります。
public class ListViewForEmbeddingInScrollView extends ListView {
public ListViewForEmbeddingInScrollView(Context context) {
super(context);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListViewForEmbeddingInScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 4, MeasureSpec.AT_MOST));
}
}
heightMeasureSpecを非常に大きなサイズ(Integer.MAX_VALUE >> 4)でAT_MOSTに操作すると、ListViewは指定された(非常に大きな)高さまでのすべての子を測定し、それに応じて高さを設定します。
これは、いくつかの理由で他のソリューションよりもうまく機能します。
- すべてを正しく測定します(パディング、ディバイダー)
- メジャーパス中にListViewを測定します
- #2により、追加のコードなしで、アイテムの幅または数の変更を正しく処理します
マイナス面としては、これを行うことは、SDKの文書化されていない動作に依存しているため、変更される可能性があるということです。一方、これがwrap_contentが実際にListViewで機能する方法であり、現在のwrap_contentの動作が壊れていると主張することもできます。
将来的に動作が変更される可能性がある場合は、onMeasure関数と関連する関数をListView.javaから独自のサブクラスにコピーしてから、UNSPECIFIEDのonMeasure実行を介してAT_MOSTパスを作成する必要があります。
ちなみに、これは、少数のリストアイテムで作業している場合、完全に有効なアプローチだと思います。LinearLayoutと比較すると効率が悪くなる可能性がありますが、項目数が少ない場合、LinearLayoutを使用することは不必要な最適化であり、したがって不必要な複雑さになります。