[Android] ViewStub : Zero-sized view “เมื่อไรเขามา ฉันจะไป”
ตอนที่เริ่มเขียน Android หลายๆท่านคงเคยผ่านตามาบ้างกับ Android Component ที่ชื่อว่า ViewStub ซึ่งผมก็เป็นหนึ่งคนที่ได้แค่ผ่านๆตาแต่ไม่เคยลองใช้งาน วันนี้ก็เลยหยิบเอามาเขียนซักเล็กน้อยครับ
ViewStub คืออะไร ?
ViewStub คือ View ชนิดหนึ่ง มีการใช้งาน Memory น้อยมากกกกกก เนื่องจากไม่มีการเขียนอะไรลงบนจอเลย (Zero-sized View) ด้วยเหตุนี้ ViewStub จึงไม่ปรากฏบนจอ
โดยที่ไม้เด็ดของ ViewStub คือ สามารถ Inflate View อื่นๆ เข้ามาแทนที่ตัวมันเอง ในขณะ Runtime ได้ เพียงแค่เรียกใช้คำสั่ง ViewStub.inflate()
หรือ ViewStub.setVisibility()
ซึ่งเป็นที่มาของหัวข้อเรื่องที่ว่า “เมื่อไรเขามา ฉันจะไป” นั่นเอง
ใช้งานเมื่อไร ?
ViewStub เหมาะสำหรับการใช้งานกับ View ที่ไม่ได้แสดงผลทุกครั้งในหน้าเดิมๆ หรือ View ที่นานๆทีจะแสดงผลสักครั้งนึง เช่น แถบคาดว่า User ถูกแบน, Progress bar แสดง % ในการ Download ข้อมูล เป็นต้น
เนื่องจากว่า ViewStub ไม่มีการแสดงผลลงบนจอและมี View Hierarchy เพียงชั้นเดียว จึงทำให้ใช้งาน Memory น้อยกว่ามาก เมื่อเทียบกับการที่ใส่ View ลงไปตรงๆใน XML แล้วสั่ง visibility="gone"
เพราะถึงแม้ว่าจะซ่อนไปแล้ว View นั้นๆก็ยังจะโดน Inflate อยู่ดี ซึ่งก็หมายถึง Memory ที่ต้องเสียไปโดยเปล่าประโยชน์ นั่นเอง :(
การใช้งาน
หน้าตาของ ViewStub ในไฟล์ .xml
android:inflatedId คือ การกำหนด Id ให้กับ View ที่ Inflate มาแทน ViewStub
android:layout คือ ไฟล์ layout .xml ที่ต้องการให้มาแทน ViewStub
และเมื่อต้องการให้ View อื่นมาแทนที่ ViewStub ก็เพียงเรียกคำสั่งดังตัวอย่าง
การใช้งาน ViewStub ก็มีเพียงเท่านี้ แต่บางท่านอาจจะยังงงๆอยู่ เพื่อความเข้าใจมากขึ้นเราลองมาทำ Work Shop กันดีกว่าครับ :)
ลองทำ Work Shop ง่ายๆกันดีกว่า
โจทย์คือ
— หาก User อยู่ในสถานะปกติ ก็ให้แสดง Avatar ของ User (A)
— แต่หาก User ถูกแบน ให้แสดง Overlay สีดำทับพร้อมกับแสดงข้อความ (B)
1. สร้าง Layout ของ User Avatar
ขอตั้งชื่อว่า activity_user.xml ก็จะได้ผลลัพธ์จะได้ดังรูป (A) ด้านบน
2. ลองเพิ่ม Layout ของ Overlay สีดำและข้อความลงไปใน Layout เดิม
ผลลัพธ์จะได้ดังรูป (B) ด้านบน
จริงๆ แล้วทำเพียงเท่านี้ก็เพียงพอต่อความต้องการของโจทย์แล้ว แต่เดี๋ยวก่อน Layout Overlay สีดำไม่ได้แสดงทุกครั้งใช่ไหมครับ :) แล้วเราจะทำยังไงหละ??
ถูกต้องนะคร้าบบบ ViewStub ช่วยท่านได้ ลองมาดูกันดีกว่า
3. ย้าย Layout ของ Overlay สีดำและข้อความ ไปไว้อีกไฟล์นึง
ขอตั้งชื่อว่า banned_user.xml
Warning!! — View ที่จะ Inflate เข้ามาแทน ViewStub ไม่รองรับการใช้งาน tag <merge /> นะครับ
4. กลับไปที่ activity_user.xml เพื่อเพิ่ม ViewStub
การกำหนด View ที่จะมาแทน ViewStub ทำได้ด้วยการกำหนด property android:layout="@layout/banned_user"
ให้ ViewStub
5. เมื่อ User ถูกแบน ให้เรียกใช้คำสั่ง ViewStub.inflate()
เพียงเท่านี้ก็จะได้ผลลัพธ์ตามที่โจทย์ต้องการ พร้อมทั้งยังได้ Application ที่ประสิทธิภาพอีกด้วยนะครับ
แอบดูเบื้องหลังกันหน่อย
ลองมาดู View Hierarchy ระหว่างตอนที่ยังเป็น ViewStub (1) และหลังจาก Inflate View (2) อื่นเข้ามาแทนกันหน่อย
จะเห็นได้ว่า android:inflatedId
ที่กำหนดไว้ให้กับ ViewStub ถูกกำหนดเป็น ID ให้กับ View ที่ถูก Inflate เข้ามาแทนนั่นเอง ส่วนเรื่อง View Hierarchy จากภาพด้านบนคงจะพอบอกได้แล้วว่า ViewStub ดียังไง
สำหรับเรื่องของ ViewStub คงจบลงเท่านี้ สุดท้ายหากมีข้อสงสัยหรือแนะนำก็ฝากไว้ใน Comment ได้เลยนะครับ ขอบคุณครับ
ปล. ดูโค้ดทั้งหมดได้ที่ github.com
ลิงค์อ้างอิง
— ViewStub
— Delayed Loading of Views
— Android Layout Tricks #3: Optimize with stubs