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 ให้เป็น AT_MOST ที่มีขนาดใหญ่มาก (Integer.MAX_VALUE >> 4) ทำให้ ListView วัดลูกทั้งหมดของมันจนถึงความสูงที่กำหนด (ใหญ่มาก) และตั้งค่าความสูงตามนั้น
สิ่งนี้ทำงานได้ดีกว่าโซลูชันอื่น ๆ ด้วยเหตุผลบางประการ:
- มันวัดทุกอย่างถูกต้อง (padding, dividers)
- มันวัด ListView ในระหว่างการวัดผ่าน
- เนื่องจาก # 2 มันจัดการการเปลี่ยนแปลงความกว้างหรือจำนวนรายการอย่างถูกต้องโดยไม่ต้องมีรหัสเพิ่มเติมใด ๆ
ในข้อเสียคุณสามารถยืนยันว่าการทำเช่นนี้ขึ้นอยู่กับพฤติกรรมที่ไม่มีเอกสารใน SDK ซึ่งสามารถเปลี่ยนแปลงได้ ในอีกทางหนึ่งคุณอาจโต้แย้งว่านี่เป็นวิธีที่ wrap_content ควรทำงานกับ ListView และพฤติกรรมของ wrap_content ปัจจุบันเสีย
หากคุณกังวลว่าพฤติกรรมนี้อาจเปลี่ยนแปลงได้ในอนาคตคุณควรคัดลอกฟังก์ชัน onMeasure และฟังก์ชั่นที่เกี่ยวข้องออกจาก ListView.java และลงในคลาสย่อยของคุณเอง
โดยวิธีการที่ฉันเชื่อว่านี่เป็นวิธีที่ถูกต้องสมบูรณ์แบบเมื่อคุณทำงานกับรายการจำนวนน้อย อาจไม่มีประสิทธิภาพเมื่อเปรียบเทียบกับ LinearLayout แต่เมื่อจำนวนรายการมีขนาดเล็กการใช้ LinearLayout เป็นการเพิ่มประสิทธิภาพที่ไม่จำเป็นดังนั้นจึงมีความซับซ้อนที่ไม่จำเป็น