ปัญหาพื้นฐานคือว่าคุณต้องรอสำหรับขั้นตอนการวาดภาพสำหรับการวัดจริง (โดยเฉพาะอย่างยิ่งที่มีค่าแบบไดนามิกเช่นwrap_content
หรือmatch_parent
) onResume()
แต่โดยปกติขั้นตอนนี้ยังไม่ได้รับการเสร็จสิ้นถึง ดังนั้นคุณต้องมีวิธีแก้ปัญหาเพื่อรอขั้นตอนนี้ มีวิธีแก้ไขปัญหาต่าง ๆ ที่เป็นไปได้สำหรับสิ่งนี้:
1. ฟังกิจกรรม Draw / Layout: ViewTreeObserver
ViewTreeObserver เริ่มทำงานแล้วสำหรับกิจกรรมการวาดรูปที่แตกต่างกัน โดยทั่วไปOnGlobalLayoutListener
คือสิ่งที่คุณต้องการรับการวัดดังนั้นโค้ดในผู้ฟังจะถูกเรียกหลังจากเฟสเลย์เอาต์ดังนั้นการวัดจึงพร้อม:
view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
view.getViewTreeObserver().removeOnGlobalLayoutListener(this);
view.getHeight(); //height is ready
}
});
หมายเหตุ: ผู้ฟังจะถูกลบออกทันทีเพราะมิฉะนั้นจะเริ่มทำงานในทุกรูปแบบเหตุการณ์ หากคุณต้องสนับสนุนแอปSDK Lvl <16ใช้สิ่งนี้เพื่อยกเลิกการลงทะเบียนผู้ฟัง:
public void removeGlobalOnLayoutListener (ViewTreeObserver.OnGlobalLayoutListener victim)
2. เพิ่ม runnable ไปยังคิวโครงร่าง: View.post ()
ไม่ค่อยมีใครรู้จักและเป็นทางออกที่ฉันโปรดปราน โดยทั่วไปเพียงใช้วิธีการโพสต์ของ View ด้วย runnable ของคุณเอง โดยทั่วไปจะเป็นการรอคิวโค้ดของคุณหลังจากการวัด, เลย์เอาต์และอื่น ๆ ตามที่ระบุไว้โดยRomain Guy :
คิวกิจกรรม UI จะประมวลผลกิจกรรมตามลำดับ หลังจาก setContentView () ถูกเรียกใช้คิวเหตุการณ์จะมีข้อความขอให้มีการถ่ายทอดใหม่ดังนั้นสิ่งที่คุณโพสต์ลงในคิวจะเกิดขึ้นหลังจากผ่านโครงร่าง
ตัวอย่าง:
final View view=//smth;
...
view.post(new Runnable() {
@Override
public void run() {
view.getHeight(); //height is ready
}
});
ข้อดีกว่า ViewTreeObserver
:
- รหัสของคุณจะถูกดำเนินการเพียงครั้งเดียวและคุณไม่จำเป็นต้องปิดการใช้งานผู้สังเกตการณ์หลังจากการดำเนินการซึ่งอาจเป็นเรื่องยุ่งยาก
- ไวยากรณ์ verbose น้อย
อ้างอิง:
3. เขียนทับวิธี onLayout ของ Views
นี่เป็นเพียงการปฏิบัติในบางสถานการณ์เมื่อตรรกะสามารถห่อหุ้มในมุมมองของตัวเองมิฉะนั้นนี่เป็นไวยากรณ์ที่ค่อนข้างละเอียดและซับซ้อน
view = new View(this) {
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
view.getHeight(); //height is ready
}
};
นอกจากนี้โปรดทราบว่า onLayout จะถูกเรียกหลายครั้งดังนั้นโปรดคำนึงถึงสิ่งที่คุณทำในวิธีการหรือปิดใช้งานรหัสของคุณหลังจากครั้งแรก
4. ตรวจสอบว่าผ่านขั้นตอนการจัดวางหรือไม่
หากคุณมีรหัสที่รันหลายครั้งในขณะที่สร้าง UI คุณสามารถใช้วิธีการสนับสนุน v4 lib ต่อไปนี้:
View viewYouNeedHeightFrom = ...
...
if(ViewCompat.isLaidOut(viewYouNeedHeightFrom)) {
viewYouNeedHeightFrom.getHeight();
}
ผลตอบแทนจริงถ้ามุมมองที่ผ่านอย่างน้อยหนึ่งรูปแบบเพราะมันถูกแนบล่าสุดหรือแยกออกจากหน้าต่าง
เพิ่มเติม: การวัดที่กำหนดไว้แบบสแตติก
หากพอเพียงที่จะได้รับความสูง / ความกว้างที่กำหนดไว้แบบคงที่คุณก็สามารถทำได้ด้วย:
แต่โปรดจำไว้ว่านี่อาจแตกต่างกับความกว้าง / ความสูงจริงหลังจากวาด javadoc อธิบายความแตกต่างได้อย่างสมบูรณ์แบบ:
ขนาดของมุมมองแสดงด้วยความกว้างและความสูง มุมมองมีค่าความกว้างและความสูงสองคู่จริง ๆ แล้ว
คู่แรกเรียกว่าความกว้างที่วัดได้และความสูงที่วัดได้ มิติข้อมูลเหล่านี้กำหนดขนาดมุมมองที่ต้องการให้อยู่ในพาเรนต์ (ดูรายละเอียดเพิ่มเติมจากเลย์เอาต์) มิติข้อมูลที่วัดได้โดยการเรียกใช้ getMeasuredWidth () และ getMeasuredHeight ()
คู่ที่สองนั้นรู้จักกันในชื่อความกว้างและความสูงหรือบางครั้งการวาดความกว้างและความสูงของการวาด มิติข้อมูลเหล่านี้กำหนดขนาดที่แท้จริงของมุมมองบนหน้าจอ ณ เวลาวาดและหลังเค้าโครง ค่าเหล่านี้อาจ แต่ไม่จำเป็นต้องแตกต่างจากความกว้างและความสูงที่วัดได้ สามารถรับความกว้างและความสูงได้โดยโทรหา getWidth () และ getHeight ()