ScrollView 與 ListView 都擁有垂直滾動機制,觸摸事件分發衝突導致 ListView 無法正確測量高度,默認僅顯示一項。
遍歷適配器所有項目,累加測量高度,設置給 ListView:
public void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter adapter = listView.getAdapter();
if (adapter == null) return;
int totalHeight = 0;
for (int i = 0; i < adapter.getCount(); i++) {
View item = adapter.getView(i, null, listView);
item.measure(0, 0); // 測量寬高
totalHeight += item.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (adapter.getCount() - 1));
params.height += 5; // 微調邊距
listView.setLayoutParams(params);
listView.requestLayout();
}
調用時機: adapter.notifyDataSetChanged() 後或數據加載完成後。缺點: 數據變動需重新調用,項目過多時測量耗時。
核心思路:將測量模式改為 AT_MOST 並給足夠大的尺寸限制,讓 ListView 完全展開。
public class ScrollViewListView extends ListView {
public ScrollViewListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// Integer.MAX_VALUE >> 2 即 536870911,足夠大
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
使用: 在布局 XML 中直接替換 <ListView> 為 <com.yourpkg.ScrollViewListView>,無需額外 Java 代碼。
| 維度 | 動態測量法 | 自定義 View 法 |
|---|---|---|
| 代碼侵入性 | 需在邏輯層調用 | 僅替換 XML 標籤 |
| 動態數據支持 | 需手動刷新 | 自動適應 |
| 性能 | 大數據量測量慢 | 系統優化測量流程 |
| 推薦場景 | 簡單靜態列表 | 通用、生產環境首選 |
RecyclerView + NestedScrollView 並設置 setNestedScrollingEnabled(false)。ScrollView 中嵌套多個滾動視圖,嚴重影響流暢度。