ฉันบิตสับสนเกี่ยวกับบทบาทของforceLayout(), requestLayout()และinvalidate()วิธีการของViewชั้น
พวกเขาจะถูกเรียกเมื่อใด
ฉันบิตสับสนเกี่ยวกับบทบาทของforceLayout(), requestLayout()และinvalidate()วิธีการของViewชั้น
พวกเขาจะถูกเรียกเมื่อใด
คำตอบ:
เพื่อให้เข้าใจคำตอบได้ดียิ่งขึ้นโดยFrançois BOURLIEUXและDalvikฉันขอแนะนำให้คุณดูแผนภาพวงจรการดูที่ยอดเยี่ยมนี้โดยArpit Mathur :

TextViewดีว่าเป็นคำถามที่น่าสนใจและจะซื่อสัตย์ผมไม่ทราบจริงๆว่าทำไมพวกเขาเรียกวิธีการทั้งในเช่น ผมคิดว่าบางทีพวกเขาต้องการที่จะวาดViewเป็นครั้งสุดท้ายก่อนที่พวกเขาเปลี่ยนพารามิเตอร์รูปแบบที่เกี่ยวข้องกับมัน แต่มันไม่ได้โดดทำให้รู้สึกใด ๆ ถ้าเราคิดเกี่ยวกับสายที่ถูกเรียกในลำดับที่แตกต่างกัน (และพวกเขาเรียกinvalidate()ขวาหลังจากที่requestLayout()ในTextViewเช่นกัน) อาจจะสมควรได้รับคำถามอื่นใน StackOverflow
invalidate()และrequestLayout()) อย่างถูกต้อง วัตถุประสงค์ของวิธีการเหล่านั้นคือการบอกViewสิ่งที่ประเภทของการไม่ได้ (ตามที่คุณเรียกมันว่า) ได้เกิดขึ้น มันไม่เหมือนกับการViewตัดสินใจว่าจะติดตามเส้นทางใดหลังจากคุณเรียกใช้หนึ่งในวิธีการเหล่านั้น ตรรกะที่อยู่เบื้องหลังการเลือกView-lifecycle-path คือการเลือกวิธีการที่เหมาะสมในการเรียกตัวเอง หากมีบางสิ่งบางอย่างที่เกี่ยวข้องกับการเปลี่ยนขนาด - requestLayout()ควรจะเรียกว่าถ้ามีเพียงการเปลี่ยนแปลงภาพโดยไม่ต้องขนาดการเปลี่ยนแปลง - invalidate()คุณควรจะเรียก
Viewด้วยวิธีใดวิธีหนึ่งเช่นคุณได้รับLayoutParams a Viewและคุณแก้ไขได้ แต่ไม่เรียกอย่างใดอย่างหนึ่งrequestLayoutหรือsetLayoutParams(ซึ่งเรียกrequestLayoutภายใน) คุณสามารถโทรได้invalidate()มากเท่าที่คุณต้องการและViewจะไม่ไปผ่านขั้นตอนการวัดแบบการจัดวางจึงจะไม่เปลี่ยนขนาดของมัน ถ้าคุณไม่บอกคุณViewว่าขนาดของมันเปลี่ยนไป (ด้วยrequestLayoutการเรียกเมธอด) Viewมันจะถือว่ามันไม่ได้และonMeasureและonLayoutจะไม่ถูกเรียก
invalidate()การโทรinvalidate()เสร็จสิ้นเมื่อคุณต้องการกำหนดเวลาการวาดมุมมองใหม่ มันจะส่งผลให้onDrawถูกเรียกในที่สุด (เร็ว ๆ นี้ แต่ไม่ทันที) ตัวอย่างเมื่อมุมมองที่กำหนดเองจะเรียกว่าเป็นเมื่อคุณสมบัติข้อความหรือสีพื้นหลังมีการเปลี่ยนแปลง
มุมมองจะถูกวาดใหม่ แต่ขนาดจะไม่เปลี่ยนแปลง
requestLayout()requestLayout()หากสิ่งที่เกี่ยวกับมุมมองของคุณมีการเปลี่ยนแปลงที่จะมีผลต่อขนาดแล้วคุณควรจะเรียก สิ่งนี้จะทริกเกอร์onMeasureและonLayoutไม่เพียง แต่สำหรับมุมมองนี้เท่านั้น
โทรrequestLayout()จะไม่รับประกันว่าจะมีผลในการonDraw (ตรงกันข้ามกับสิ่งที่แผนภาพในคำตอบที่ได้รับการยอมรับนัย) invalidate()ดังนั้นจึงมักจะถูกรวมกับ
invalidate();
requestLayout();
ตัวอย่างนี้คือเมื่อฉลากที่กำหนดเองมีการเปลี่ยนแปลงคุณสมบัติข้อความ ฉลากจะเปลี่ยนขนาดและจำเป็นต้องปรับใหม่และวาดใหม่
forceLayout()เมื่อมีการrequestLayout()เรียกใช้กลุ่มมุมมองพาเรนต์คุณไม่จำเป็นต้องจำใหม่และถ่ายทอดมุมมองชายด์ อย่างไรก็ตามหากเด็กควรรวมอยู่ใน remeasure และ relayout คุณสามารถโทรหาforceLayout()เด็กได้ forceLayout()ใช้งานได้เฉพาะกับเด็กถ้าเกิดขึ้นร่วมกับrequestLayout()บนพาเรนต์โดยตรง การเรียกforceLayout()ด้วยตัวเองจะไม่มีผลเนื่องจากไม่ทริกเกอร์ทrequestLayout()รีมุมมอง
อ่านคำถาม & คำตอบนี้โดยละเอียดforceLayout()สำหรับรายละเอียดเพิ่มเติม
View รหัสแหล่งที่มาrequestLayout()มาก่อนinvalidate()ถ้าคุณต้องการ ไม่มีรูปแบบใดหรือวาดรูปทันที ค่อนข้างพวกเขาตั้งค่าสถานะที่ในที่สุดจะส่งผลให้การถ่ายทอดและวาดใหม่
ที่นี่คุณสามารถค้นหาคำตอบบางอย่าง: http://developer.android.com/guide/topics/ui/how-android-draws.html
สำหรับฉันการโทรเพื่อinvalidate()รีเฟรชมุมมองและการโทรเพื่อrequestLayout()รีเฟรชมุมมองและคำนวณขนาดของมุมมองบนหน้าจอ
คุณใช้โมฆะ () ในมุมมองที่คุณต้องการวาดใหม่มันจะทำให้ onDraw (Canvas c) ถูกเรียกใช้และ requestLayout () จะทำให้การเรนเดอร์เค้าโครงทั้งหมด (เฟสการวัดและเฟสการวางตำแหน่ง) ทำงานอีกครั้ง คุณควรใช้มันหากคุณเปลี่ยนขนาดของมุมมองเด็กในรันไทม์ แต่เฉพาะในบางกรณีเช่นข้อ จำกัด จากมุมมองพาเรนต์ (โดยที่ฉันหมายความว่าความสูงหรือความกว้างของพาเรนต์เป็น WRAP_CONTENT และจับคู่เด็ก ๆ
คำตอบนี้forceLayout()ไม่ถูกต้องเกี่ยวกับ
อย่างที่คุณเห็นในรหัสของforceLayout()มันแค่ทำเครื่องหมายว่า "ต้องการการถ่ายทอด" แต่มันไม่ได้กำหนดเวลาหรือทริกเกอร์การถ่ายทอดนั้น การถ่ายทอดผลจะไม่เกิดขึ้นจนกว่าจะถึงจุดหนึ่งในอนาคตที่ผู้ปกครองของมุมมองถูกวางไว้ด้วยเหตุผลอื่น
นอกจากนี้ยังมีปัญหาที่ใหญ่กว่าเมื่อใช้forceLayout()และrequestLayout():
สมมติว่าคุณโทรforceLayout()มาดู ตอนนี้เมื่อเรียกrequestLayout()ใช้การสืบทอดของมุมมองนั้น Android จะโทรหาrequestLayout()บรรพบุรุษของผู้สืบทอดนั้นซ้ำ forceLayout()ปัญหาคือว่ามันจะหยุดการเรียกซ้ำในมุมมองที่คุณได้เรียกว่า ดังนั้นการrequestLayout()โทรจะไม่ไปถึงรูทการดูและดังนั้นจึงไม่เคยกำหนดเวลาการส่งผ่านเลย์เอาต์ ทรีย่อยทั้งหมดของลำดับชั้นการดูกำลังรอเลย์เอาต์และการเรียกrequestLayout()ใช้มุมมองของทรีย่อยนั้นจะไม่ทำให้เกิดเลย์เอาต์ เฉพาะการเรียกrequestLayout()ดูมุมมองใด ๆ นอกทรีย่อยนั้นจะทำให้เวทมนต์แตก
ฉันจะพิจารณาการใช้งานforceLayout()(และวิธีที่มันมีผลต่อrequestLayout()การแตกและคุณไม่ควรใช้ฟังก์ชันนั้นในโค้ดของคุณ
Viewและโดยพบปัญหาตัวเอง & แก้จุดบกพร่องมัน
forceLayout()API: มันไม่จริงบังคับผ่านรูปแบบที่ค่อนข้างจะเป็นเพียงแค่การเปลี่ยนแปลงธงที่มีการตั้งข้อสังเกตในonMeasure()แต่onMeasure()จะไม่ถูกเรียกเว้นแต่requestLayout()หรืออย่างชัดเจนView#measure()เรียกว่า นั่นหมายถึงว่าควรจะจับคู่กับforceLayout() requestLayout()บนมืออื่น ๆ แล้วทำไมจะดำเนินการforceLayout()ถ้าฉันยังคงต้องดำเนินการrequestLayout()?
requestLayout()ทำทุกอย่างที่forceLayout()ทำด้วย
forceLayoutทำให้สมเหตุสมผล ดังนั้นในที่สุดมันก็มีชื่อและเอกสารไม่ดีมาก
invalidate()---> onDraw()จากเธรด UI
postInvalidate()---> onDraw()จากด้ายพื้นหลัง
requestLayout()---> onMeasure()และonLayout()และไม่จำเป็น onDraw()
forceLayout()---> onMeasure()และonLayout() เพียงถ้าrequestLayout()ผู้ปกครองโดยตรงเรียกว่า