23 May 2018

[Android Code] เตรียมตัวให้พร้อมกับ Display Cutout บน Android P



         ตั้งแต่ iPhone X เปิดตัวขึ้นมาพร้อมกับรอยแหว่งที่ผู้คนต่างพากันเรียกว่าติ่งหรือ Notch แต่ในทุกวันนี้ Flagship ของฝั่งแอนดรอยด์ก็พากันเปิดตัวพร้อมกับรอยแหว่งนี้เช่นกัน (แถมทำกันหลายยี่ห้อด้วยนะ) ดังนั้นจะมัวแต่ไปล้อนักพัฒนาฝั่ง iOS อย่างเดียวก็ไม่ได้ละ เพราะฝั่งแอนดรอยด์ก็ต้องมานั่งทำแอพให้รองรับกับรอยแหว่งหรือชื่ออย่างเป็นทางการที่ทางแอนดรอยด์เรียกว่า Display Cutout

        เมื่อเทรนด์ใหม่ของหน้าจอกำลังเป็นที่นิยมจึงทำให้ทีมพัฒนาแอนดรอยด์ต้องทำให้ Android P สามารถรองรับกับเทรนด์นี้ได้ในอนาคตด้วย เพื่อช่วยแก้ปัญหานักพัฒนาต้องมานั่งปวดหัวเพราะว่า Display Cutout ของแต่ละรุ่นแต่ละยี่ห้อออกแบบมาไม่เหมือนกัน ไม่ได้สามารถควบคุมได้เหมือน iPhone


        ถึงแม้ว่า Android P จะออกมารองรับเรื่อง Display Cutout ให้แล้ว แต่เครื่องที่วางขายอยู่ ณ ตอนนี้ก็ยังเป็น Android 8.0 (Oreo) กันซะส่วนใหญ่ ดังนั้นจะยังไม่รองรับ Display Cutout ของ Android P แต่ทว่าผู้ผลิตของแต่ละรุ่นแต่ละยี่ห้อก็จะพยายาม Customize UI เพื่อลดผลกระทบกับแอปฯของนักพัฒนาทั่วไปให้อยู่แล้ว แต่ในอนาคตเมื่อได้อัปเดตเป็น Android P ก็จะย้ายไปใช้ฟีเจอร์ Display Cutout บน Android P กันแทน ดังนั้นในฐานะนักพัฒนาก็แนะนำให้ทำแอปฯให้รองรับกับ Display Cutout บน Android P เป็นอย่างน้อย

        และในรุ่นต่อไปก็อาจจะได้เห็นอะไรแบบนี้จนเป็นเรื่องธรรมดา ถ้านักพัฒนาคนไหนที่ไม่ได้มีทุนมากพอที่จะไปหาเครื่องเหล่านี้มาเทส ก็หาเครื่องที่เป็น Android P มาเทสก็ได้นะ สามารถตั้งค่าให้จำลองการแสดงผลของ Display Cutout ได้ใน Developer options


         สำหรับ Display Cutout ที่มีให้ทดสอบใน Developer options จะทำให้เห็นว่าไม่ได้มีแค่รูปแบบเดียวเสมอไป


        โดยที่ System UI ของแอนดรอยด์จะปรับการแสดงผลให้เหมาะสมกับ Display Cutout อยู่แล้ว แต่นักพัฒนาก็ต้องทำให้รองรับเองนะ


        ไม่ว่าจะเป็น Display Cutout แบบไหน ถ้าเข้าใจรูปแบบการทำงานบน Android P ก็หายห่วงฮะ


        โดยที่การใช้งานบนอุปกรณ์แอนดรอยด์ทั่วไปจะเห็นหน้าจอที่มี Display Cutout มาบังบางส่วนของหน้าจออยู่ แต่ในความเป็นจริงนั้นระบบแอนดรอยด์ก็ยังคงแสดงผลเต็มหน้าจอตามปกติ ดังนั้นเมื่อบันทึกภาพหน้าจอมาดูก็จะไม่เห็น Display Cutout ติดมาด้วย

รูปแบบในการแสดงผลสำหรับ Display Cutout

        นักพัฒนาสามารถกำหนดได้ว่าจะให้ Display Cutout แสดงผลยังไงผ่าน styles.xml ด้วย Attribute ที่ชื่อว่า

<item name="android:windowLayoutInDisplayCutoutMode">never|default|shortEdges</item>


        ถ้าไม่ได้กำหนดอะไร ก็จะถือว่าเป็น Default เสมอ โดยที่ Default จะเป็นการแสดง Status Bar คลุม Display Cutout อีกทีหนึ่ง แต่จะไม่มีผลเมื่อแสดงหน้าจอแบบ Fullscreen

        แต่ถ้ากำหนดเป็น Never จะเป็นการซ่อน Display Cutout ด้วยการเปลี่ยนพื้นหลังของ Status Bar ให้เป็นสีดำแทน ซึ่งเหมาะกับการแสดงผลที่ไม่ต้องการให้เห็น Display Cutout จะใช้กับ Fullscreen ก็ได้เหมือนกันนะ

         ทั้ง Default และ Never จะแสดงผลต่างกันในแนวตั้ง แต่จะแสดงผลเหมือนกันในแนวนอน โดยจะไม่เห็น Display Cutout ที่อยู่ด้านข้าง


        สำหรับ Short Edges นั้นจะใช้กับตอนแสดงผล Fullscreen เท่านั้น โดยจะยอมให้ Layout ขยายเต็มจอจนโดน Display Cutout บัง​ ซึ่งมีผลทั้งตอนแสดงผลในแนวตั้งและแนวนอน


แล้วนักพัฒนาต้องทำอะไรบ้าง เพื่อให้รองรับ Display Cutout

         ในกรณีที่สร้าง Layout ขึ้นมาจากใน Android Studio โดยที่ไม่ได้ Custom Style อะไรเพิ่มเติมเลย ก็ไม่ต้องทำอะไร

// styles.xml

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

        เวลาแสดงผลในแนวตั้ง Status Bar ก็จะยืดความสูงให้พอดีกับ Display Cutout และถ้าแสดงผลเป็นแนวนอนก็จะถูกบีบหน้าจอให้ไม่เห็นส่วนที่เป็น Display Cutout

มีปัญหาอย่างอื่นอีกมั้ย?

        ถ้าทำ Collapsing Toolbar ก็ไม่น่าจะมีปัญหาอะไร เพราะต้องกำหนด Display Cutout เป็นแบบ Default อยู่แล้ว เพราะงั้นพวก Toolbar ทั้งหมดทั้งมวลควรทำงานได้ตามปกติ (ถ้าแสดงผลไม่ถูกก็ถือว่าเป็นบั๊กของ Design Support น่ะแหละ)

        แต่สำหรับผู้ที่หลงเข้ามาอ่านที่กำหนด 

android:fitsSytemWindows="true"

        เพื่อให้ Content บางส่วนแสดงผลเต็มหน้าจอ (กินพื้นที่ของ Status Bar ด้วย) ก็ต้องระวังด้วยนะ เพราะว่าเครื่องที่มี Display Cutout จะมี Status Bar สูงกว่าชาวบ้านเค้า ดังนั้นอาจจะทำให้กินพื้นที่ Content เข้ามากกว่าที่เผื่อไว้


สำหรับการแสดงผลที่ต้องคำนวณผ่านโค้ด

        ผู้ที่หลงเข้ามาอ่านบางคนอาจจะต้องวุ่นวายกับ Graphic ไม่ว่าจะเป็นพวก Canvas, OpenGL หรือ Graphic Engine อื่นๆ อาจจะต้องมีการคำนวณพื้นที่ในการแสดงผลเอง ดังนั้น Display Cutout จึงมี API ให้ด้วย จะได้รู้ว่าตำแหน่งของ Display Cutout อยู่ตรงไหนบ้าง

        โดยคลาส DisplayCutout นั้นอยู่ใน WindowInsets ที่เป็นจะช่วยบอก Safe Area ให้นักพัฒนารู้ได้

val displayCutout : DisplayCutout
val layoutContainer : ViewGroup
...
override fun onCreate(savedInstanceState: Bundle?) {
    ...
    layoutContainer.setOnApplyWindowInsetsListener({ _, insets ->
        displayCutout = insets.displayCutout
        insets
    })
}

        View หรือ ViewGroup จะมีคำสั่งที่ชื่อว่า setOnApplyWindowInsetsListener(...) ให้ใส่ไว้ใน onCreate(...) เพื่อดึงข้อมูลของ DisplayCutout ออกมาใช้งานได้

        และสมมติว่า layoutContainer แสดงผลเต็มหน้าจอแบบ Fullscreen นะ

        เวลาที่เจ้าของบล็อกอยากจะรู้ว่ามี Display Cutout อยู่ที่ไหนบ้าง จะต้องเช็คค่าที่อยู่ในคำสั่ง getBoundingRects() แบบนี้

displayCutout?.boundingRects?.forEach {
    val top = it.top
    val bottom = it.bottom
    val left = it.left
    val right = it.right
    ...
}

         คำสั่ง getBoundingRect() จะส่งค่าออกมาเป็น List<Rect> เพราะว่า Display Cutout ไม่ได้มีแค่ตำแหน่งเดียวเท่านั้น อย่างเช่น Double Display Cutout ที่มี Display Cutout ทั้งบนและล่างของหน้าจอ

         เมื่อได้ตำแหน่งของ Display Cutout เป็นคลาส Rect ก็จะทำให้ผู้ที่หลงเข้ามาอ่านรู้ได้ว่าอยู่ที่ตำแหน่งไหนโดยเช็คจาก Top, Bottom, Left และ Right


         หรือถ้าไม่สนใจว่า Display Cutout อยู่ตรงไหน ขอแค่แสดงผลโดยไม่โดน Display Cutout ทับก็พอ ให้ใช้คำสั่งแบบนี้แทน

val top = displayCutout?.safeInsetTop
val bottom = displayCutout?.safeInsetBottom
val left = displayCutout?.safeInsetLeft
val right = displayCutout?.safeInsetRight

        คำสั่งดังกล่าวจะบอกว่าพื้นที่ตรงไหนที่ Safe Area


สรุป

        ต้องยอมรับว่าในวันข้างหน้านักพัฒนาจะต้องเจอกับอุปกรณ์แอนดรอยด์ที่มี Display Cutout อย่างเลี่ยงไม่ได้ ดังนั้นทางที่ดีก็ควรเช็คซักหน่อยว่าแอปฯของผู้ที่หลงเข้ามาอ่านนั้นแสดงผลได้ปกติหรือไม่ แต่ถ้าไม่ได้กำหนดค่าสำหรับ Display Cutout ก็ไม่น่าจะส่งผลกระทบอะไรมากนัก เพราะว่า Android P จัดการให้แล้วส่วนหนึ่ง แต่กรณีที่แอปฯนั้นมีการทำ Theme แบบ Translucent หรือ Fullscreen ก็อาจจะโดนผลกระทบของ Display Cutout ได้

        สำหรับผู้ที่หลงเข้ามาอ่านที่กลัวว่าการมาของ Display Cutout นั้นจะทำให้พื้นที่ในการแสดงผลน้อยลง ก็หายห่วงได้เลย เพราะว่าอุปกรณ์แอนดรอยด์ที่มี Display Cutout มักจะมาพร้อมกับหน้าจออัตราส่วน 18:9 ขึ้นไปอยู่แล้ว ดังนั้นต่อให้มี Display Cutout ก็จะมีพื้นที่ให้แอปฯแสดงผลไม่ต่ำกว่า 16:9 แน่นอน

แหล่งข้อมูลอ้างอิง

        • Display Cutout [Android Developers]
        • Exploring Android P: Display Cutouts [Medium]




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium