ถ้าพูดถึงการทำให้แอปฯแสดงหน้าจอแบบ Fullscreen หรือ Immersive ก็คงจะร้องอ๋อกัน ซึ่งในบทความนี้ก็จะขอพูดถึงการควบคุมการทำงานของ System UI ภายในแอปฯกันครับ
เนื้อหาในบทความนี้จะไม่ได้พูดถึง WindowInsets API ตัวใหม่ของ Android 11
ซึ่ง System UI ที่ว่านี้ก็หมายถึง Status Bar, Navigation Bar และ Action Bar (หรือ Toolbar) ที่คุ้นเคยกันดีนั่นเอง ซึ่งระบบแอนดรอยด์ก็เปิดให้แอปฯสามารถเปลี่ยนรูปแบบการแสดงผลของ System UI ให้เหมาะกับการใช้งานแอปฯในแต่ละรูปแบบได้
ซึ่งควบคุมยังไงได้บ้างนั้นก็จะขึ้นอยู่กับเวอร์ชันของแอนดรอยด์ด้วย เพราะเวอร์ชันเก่าๆก็อาจจะทำงานบางอย่างไม่ได้ แต่จะมีอะไรบ้างนั้นมาดูกันต่อเลย
Dimming หรือ Low Profile
เป็นความสามารถที่ถูกเพิ่มเข้ามาตั้งแต่สมัย Android 4.0 Ice Cream Sandwich (API Level 14) โดยจะลดการแสดงผลของ Status Bar และ Navigation Bar ให้รบกวนผู้ใช้น้อยลง ซึ่งเหมาะกับแอปที่มีเนื้อหาที่ผู้ใช้ต้องดูเป็นระยะเวลานาน และไม่อยากให้การทำงานส่วนอื่นๆมารบกวนสายตาของผู้ใช้
เมื่อเปิดใช้งาน Dimming หรือ Low Profile ผู้ใช้จะเห็นแค่ระดับแบตเตอรีที่ Status Bar เท่านั้น ส่วนไอคอนอื่นๆรวมไปถึง Notification จากแอปต่างๆจะถูกซ่อนออกไป ในขณะเดียวกันปุ่มที่อยู่บน Navigation Bar ก็จะปรับสีเพื่อลด Contrast ลงไปด้วย
การแสดงผลแบบ Dimming หรือ Low Profile จะต้องใช้คำสั่งแบบนี้
val window: Window = /* ... */
val decorView: View = window.decorView
decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
จะเรียกใช้งานเมื่อไรก็ได้ โดยที่ Dimming จะไม่ถูกยกเลิกจนกว่าผู้ใช้จะกดที่ Status Bar/Navigation Bar หรือใช้คำสั่งเพื่อยกเลิกแบบนี้
val window: Window = /* ... */
val decorView = window.decorView
decorView.systemUiVisibility = 0
การแสดง Status Bar
เวลาที่ต้องการซ่อน Status Bar จะต้องกำหนด Flag ให้กับ setSystemUiVisibility(...)
แบบนี้
val window: Window = /* ... */
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_FULLSCREEN
และถ้าอยากให้ Status Bar กลับมาแสดงอีกครั้งก็ให้เคลียร์ค่าเป็น 0 ซะ
val window: Window = /* ... */
window.decorView.systemUiVisibility = 0
และเมื่อ Status Bar มีการซ่อนหรือแสดงจะทำให้ UI ของแอปมีการปรับความสูงเพื่อให้พอดีกับขนาดหน้าจอด้วย
การแสดง Navigation Bar
สำหรับการควบคุม Navigation Bar นั้นจะทำได้ตั้งแต่ Android 4.1 Jelly Bean (API Level 16) ขึ้นไป โดยมีคำสั่งคล้ายกันกับของ Status Bar เลย แต่ว่าจะใช้ Flag ที่แตกต่างกันเล็กน้อย
// คำสั่งซ่อน Navigation Bar
val window: Window = /* ... */
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
// คำสั่งแสดง Navigation Bar
val window: Window = /* ... */
window.decorView.systemUiVisibility = 0
แน่นอนว่าเมื่อ Navigation Bar มีการซ่อนหรือแสดงก็จะทำให้ UI ของแอปปรับความสูงให้พอดีกับหน้าจอด้วยเช่นกัน
การแสดง Navigation และ Status Bar พร้อมๆกัน
เนื่องจากคำสั่ง setSystemUiVisibility
เป็นการกำหนดค่าแบบ Flag ดังนั้นจึงกำหนดค่าหลายๆตัวพร้อมๆกันได้ จึงทำให้สามารถซ่อน/แสดง Navigation Bar และ Status Bar ไปพร้อมๆกันได้เลย
// คำสั่งซ่อน Navigation Bar และ Status Bar
val window: Window = /* ... */
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN
// คำสั่งแสดง Navigation Bar และ Status Bar
val window: Window = /* ... */
window.decorView.systemUiVisibility = 0
Immersive Fullscreen
จากที่ผ่านมาจะเห็นว่าถ้าอยากให้แอปฯสามารถแสดงผลแบบ Fullscreen ได้ ก็จะต้องเขียนโค้ดเพิ่มเข้าไปเอง ซึ่งยังไม่รวมไปถึงการออกจากโหมด Fullscreen และการทำปุ่มเพื่อกดออกจาก Fullscreen ก็อาจจะดูไม่สะดวกเสมอไป ดังนั้นบน Android 4.4 KitKat (API 19) จึงได้เพิ่มความสามารถในการแสดงผลแบบ Fullscreen ให้สะดวกและง่ายมากขึ้นโดยมีชื่อเรียกว่า Immersive Fullscreen
ประโยชน์หลักๆของ Immersive Fullscreen คือนักพัฒนาไม่ต้องจัดการอะไรเกี่ยวกับการแสดงผลมากนัก นอกจากสั่งแค่ให้มันแสดงผลเป็นแบบ Immersive Fullscreen เท่านั้น
โดยคำสั่งของ Immersive Fullscreen จะใช้คำสั่งแบบนี้
val window: Window = /* ... */
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE
เมื่อคำสั่งทำงาน แอปฯก็จะเข้าสู่ Immersive Fullscreen ทันที และในกรณีที่แอปฯนั้นๆเพิ่งจะแสดงเป็น Immersive Fullscreen ครั้งแรก จะมีหน้าต่างแสดงให้ผู้ใช้รับรู้ด้วย
สำหรับการออกจาก Immersive Fullscreen สามารถทำได้ด้วยปัดนิ้วที่ขอบด้านบนหรือด้านล่างของหน้าจอ ก็จะออกจาก Immersive Fullscreen ทันที
โดยการทำงานของ Immersive Fullscreen นั้นจะมีสองแบบด้วยกัน คือแบบ Non-Sticky Immersion และ Sticky Immersion
Non-Sticky Immersion
เป็นการเข้าสู่ Immersive Fullscreen เพียงแค่ครั้งเดียว จนกว่าผู้ใช้จะกดออก ซึ่งใช้คำสั่งเดียวกันกับที่เจ้าของบล็อกยกตัวอย่างในตอนแรกนั่นแหละ
val window: Window = /* ... */
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE
เหมาะสำหรับแอปฯที่ต้องการแสดงผลแบบ Immersive Fullscreen ในการใช้งานบางอย่างเท่านั้น
Sticky Immersion
แต่ถ้าเกิดอยากจะให้แอปแสดงผลแบบ Immersive Fullscreen ตลอดเวลาเลย ก็ให้ใช้คำสั่งแบบนี้
val window: Window = /* ... */
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
View.SYSTEM_UI_FLAG_FULLSCREEN or
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
โดยคำสั่งจะคล้ายๆกับก่อนหน้านี้เลย ต่างกันแค่ตรง View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
เท่านั้นเอง
ซึ่งผลลัพธ์จะออกมาเป็นลักษณะแบบนี้
จะเห็นว่าผู้ใช้จะอยู่ในโหมด Fullscreen เสมอ เมื่อมีการลากนิ้วที่ขอบข้างบน/ล่างของหน้าจอ ก็จะเป็นการแสดง Status Bar กับ Navigation Bar และเมื่อผ่านไปซักพักก็จะซ่อนเองโดยอัตโนมัติ
การกรณีที่ใช้ Immersive Fullscreen แบบ Sticky เจ้าของบล็อกแนะนำว่าให้ใส่โค้ดลงใน onWindowFocusChanged
ได้เลย เพื่อที่ว่าจะได้เข้า Immersive Fullscreen ทันทีที่เข้าสู่หน้า Activity นั้นๆ
class MainActivity : Activity() {
/* ... */
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) {
val decorView = window.decorView
decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
}
}
}
การซ่อน Title/Action Bar และ Status Bar ผ่าน Theme
นอกเหนือจากการสั่งงานผ่านโค้ด Java แล้ว ยังสามารถกำหนดให้แสดงผลแบบ Fullscreen ได้ด้วยการกำหนด Theme ให้กับ Activity ที่ต้องการได้เลย
สามารถกำหนด Theme ให้มี Parent เป็น Theme ที่เป็น Fullscreen ได้เลย
จากภาพข้างบนก็จะเห็นว่าการสั่งให้ Fullscreen เพื่อซ่อน Status Bar นั้นจะมาพร้อมกับการซ่อน Title/Action Bar เสมอ ซึ่งก็ไม่เข้าใจเหมือนกันว่าทำไม
แต่ถ้าอยากจะซ่อนเฉพาะ Status Bar จริงๆก็กำหนดเพิ่มเข้าไปใน Theme ที่ใช้อยู่ได้เลย
<resources>
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<item name="android:windowFullscreen">true</item>
<!-- ... -->
</style>
<!-- ... -->
</resources>
เพียงเท่านี้ Theme ของผู้ที่หลงเข้ามาอ่านก็จะกลายเป็น Theme ที่ซ่อน Status Bar และผู้ใช้ก็ยังคงสามารถปัดนิ้วที่ขอบบนของจอเพื่อแสดง Status Bar ชั่วคราวได้
แต่วิธีแบบนี้จะไม่สามารถซ่อน Navigation Bar ผ่าน Theme ได้นะ
สรุป
การควบคุม System UI นั้นก็คือการซ่อน/แสดง Status Bar และ Navigation Bar นั่นเอง ซึ่งสามารถทำได้หลายแบบ โดยขึ้นอยู่กับความต้องการใช้งาน
ซึ่งจะมีรูปแบบต่างๆดังนี้
- Dimming
- Show/Hide Status Bar
- Show/Hide Navigation Bar
- Fullscreen
- Immersive Fullscreen
- Show/Hide Status Bar with Theme
สุดท้ายแล้วก็ขอให้เลือกใช้งานตามความเหมาะสมนะครับ