17 มีนาคม 2556

[Android Design] แท้จริงแล้วหน่วย dp คืออะไร?


        น่าจะรู้จักกันอยู่แล้วกับหน่วย dp บนแอนดรอยด์ จะเห็นว่าเวลากำหนดขนาดในหน้า Layout ทีไร จะใช้หน่วยเป็น dp ตลอด (หน่วยอื่นก็ได้ แต่ dp ดีสุด)

        ในบทความนี้แหละ เจ้าของบล็อกจะมาแถลงไขเจ้าหน่วย dp นี้ ว่าแท้จริงแล้วมีที่มียังไง และมีดียังไง

        สำหรับผู้ที่หลงเข้ามาอ่านคนใดยังไม่ได้อ่านเรื่อง Size และ Density ไปอ่านก่อนที่ [Android Design] ว่าด้วยเรื่อง Size และ Density ของหน้าจอ เพื่อที่จะได้เข้าใจในบทความนี้ได้มากขึ้น เพราะมันเกี่ยวข้องกัน

        ก็เป็นที่รู้กันอยู่แล้วว่าบนแอนดรอยด์นั้นมีขนาดหน้าจอที่ต่างกัน ไม่ว่าจะเป็น 480x320, 800x480, 960x540, 1280x720 บลาๆ ดังนั้นการเขียนแอปพลิเคชันจะกำหนดพิกเซลตายตัวไม่ได้เด็ดขาด ไม่เช่นนั้นแล้ว เวลาไปเปิดบนหน้าจอที่มีความละเอียดต่างกัน ก็จะทำให้การแสดงภาพเพี้ยนไปจากเดิมที่กำหนดไว้

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

        สำหรับหน่วย dp เจ้าของบล็อกขอนิยามให้กับหน่วยนี้คร่าวๆว่า

        เป็นหน่วยของความละเอียดหน้าจอ ที่สมมติขึ้นมาในแอนดรอยด์ โดยอิงจาก Resolution, Size และ Density ของจอบนเครื่องนั้นๆ

        โดยขนาดของหน่วย dp จะแบ่งออกตามขนาดหน้าจอดังนี้


                • small จะมีขนาดจออย่างน้อย 426 x 320 dp

                • normal จะมีขนาดจออย่างน้อย 470 x 320 dp

                • large จะมีขนาดจออย่างน้อย 640 x 480 dp

                • xlarge จะมีขนาดจออย่างน้อย 960 x 720 dp


        ที่เจ้าของบล็อกบอกในข้างต้นนี้เป็นหน่วย dp นะ ไม่ใช่ px แต่เดี๋ยวจะเห็นว่าจาก px มาเป็น dp แล้วเป็นแบบนี้ได้ยังไง

        ทีนี้มาดูการแปลงค่าจาก px มาเป็น dp กันก่อนดีกว่า

การแปลงจากหน่วย px ไปเป็น dp
dp = px * (160 / dpi)

การแปลงจากหน่วย dp ไปเป็น px
px = dp * (dpi / 160) 

        สำหรับ dpi จะเปรียบเสมือนค่าคงที่ของ Density โดยที่

                • ldpi จะมี dpi เท่ากับ 120

                • mdpi จะมี dpi เท่ากับ 160

                • tvdpi จะมี dpi เท่ากับ 213

                • hdpi จะมี dpi เท่ากับ 240

                • xhdpi จะมี dpi เท่ากับ 320

                • xxhdpi จะมี dpi เท่ากับ 480

                • xxxhdpi จะมี dpi เท่ากับ 640



        สมมติว่าลองคำนวณหาค่า dp จาก Samsung Galaxy Note 10.1 เดิมทีเครื่องนี้จะเป็น xlarge-mdpi ดังนั้นค่า dpi จะเท่ากับ 160 และเครื่องนี้มีความละเอียดหน้าจอเท่ากับ 1280 x 800

                • 1280 px : 1280 x ( 160 / 160 ) = 1280 dp

                • 800 px   : 800 x ( 160 / 160 ) = 800 dp

        ก็จะเห็นว่า เครื่องนี้มีขนาด 1280 x 800 dp จะตรงกับที่ว่า xlarge จะต้องอย่างน้อย 960 x 720 dp



        คราวนี้ลองคำนวณหาค่า dp จาก Samsung Nexus 10 ดูบ้าง เดิมทีเครื่องนี้จะเป็น xlarge-xhdpi ดังนั้นค่า dpi จะเท่ากับ 320 และเครื่องนี้มีความละเอียดหน้าจอเท่ากับ 2560 x 1600

                • 2560 px : 2560 x ( 160 / 320 ) = 1280 dp

                • 1600 px   : 1600 x ( 160 / 320 ) = 800 dp

        จะเห็นว่ามีขนาดหน้าจอเป็น 1280 x 800 dp ซึ่งมีขนาดเท่ากับ Note 10.1 ทีเป็น xlarge เหมือนกัน


        ถ้าเครื่องที่เป็น xlarge แต่ความละเอียดจอ 1024 x 600 px ล่ะ เครื่องนั้นก็จะเป็น xlarge-ldpi ดังนั้นค่า dpi ก็จะเท่ากับ 120 เมื่อคำนวณออกมาแล้วก็จะได้ขนาด 1365.33 x 799.99 dp

        ซึ่งความกว้างของจอไม่เท่ากันก็ไม่ได้สำคัญนัก เพราะขึ้นอยู่กับเครื่องนั้นว่าใช้อัตราส่วนเท่าไร 16 : 9 บ้าง 16 : 10 บ้าง หรือ 4 : 3 ก็มีเช่นกัน

        ดังนั้นจะซีเรียสกันที่ ด้านที่ค่า dp น้อยสุด (Shortest-width) เพราะว่าอุปกรณ์แอนดรอยด์หมุนเครื่องไปมาได้ ความสูงกับความกว้างจึงขึ้นอยู่กับว่าแนวตั้งหรือแนวนอน จึงใช้วิธีพิจารณาจากด้านที่ dp น้อยสุดของเครื่องแทน


        ก็จะเห็นว่าค่า dp ด้านที่น้อยสุดจะมีค่าเป็น 800 dp เหมือนกัน แต่สำหรับค่า dp ขั้นต่ำสุดของ xlarge จะเป็น 720 dp เครื่องที่ยกตัวอย่างมาก็มีขนาดใหญ่กว่าขั้นต่ำเล็กน้อย ดังนั้นเวลาออกแบบหน้า UI ของแอปพลิเคชันสำหรับ xlarge ก็ให้อิงจากด้านที่สั้นที่สุดว่าไม่ควรจะเกิน 720 dp เครื่องที่มีด้านสั้นที่สุด 800 dp ก็ยังเปิดได้ไม่เพี้ยน จะมีพื้นที่ว่างข้างๆแทน เพราะขนาดที่ใหญ่กว่า

        จริงๆแล้ว 960 x 720 dp คือเครื่อง xlarge ที่ใช้หน้าจอเป็น 4 : 3 แต่ที่คำนวณออกมาได้เป็น 1280 x 720 dp เป็นเครื่องที่ใช้ 16 : 9 และสำหรับที่คำนวณได้เป็น 1280 x 800 dp เป็นเครื่องที่ใช้ 16 : 10 ดังนั้นจึงแนะนำให้สร้าง UI โดยอิงจาก 960 x 720 dp เป็นหลัก

        แต่จากรูปข้างบนนี้จะเห็นว่าระหว่าง 960 dp กับ 1280 dp จะมีพื้นที่เหลือมากไป ก็ให้ขยายเต็มจอ (match_parent) ก็ได้ ถ้าต้องการสร้าง UI ที่ยาวกว่า 960 dp ก็ให้ใช้เป็น Scroll View ให้เลื่อนขึ้นลงได้ แต่อีกด้านต้องอย่าสร้าง UI เกิน 720 dp



        ก่อนจะจบบทความนี้ ลองยกตัวอย่างเครื่องที่เป็น normal บ้าง เพราะขนาด normal จะเห็นความแตกต่างของขนาดหน้าจอ px ได้ง่าย


        จะเห็นว่า แต่ละเครื่องจะใกล้เคียงกัน โดยจะเป็น 320 กับ 360 ถ้าจะสร้าง Layout ให้รองรับทุก Density ของขนาด normal ก็ควรจะอยู่ในขนาด 420 x 320 dp หรือว่าจะให้เกิน 420 dp ก็ได้ แล้วใช้ Scroll View ให้เลื่อนขึ้นลง แต่ความกว้างห้ามเกิน 320 dp ก็จะออกแบบ Layout ให้รองรับกับ Normal ได้ทุก Density แล้ว


        สรุปได้ว่าหน่วย dp จะช่วยให้เครื่องที่มี Size เหมือนกัน แต่ Resolution ที่ต่างกัน แปลงออกมาใกล้เคียงกันหรือเท่ากัน นี่จึงเป็นสาเหตุว่าทำไมในการออกแบบ UI แอนดรอยด์ จึงใช้หน่วย dp กันเป็นหลัก เพราะจะทำให้คลาดเคลื่อนได้น้อย

        บทความแบบภาคปฏิบัติ รอไปก่อนนะ 555



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

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