10 June 2012

Supporting Multiple Screens - การรองรับหน้าจอที่หลากหลาย

Updated on

 
        ข้อมูลในการออกแบบแอพพลิเคชันบนแอนดรอยด์ เจ้าของบล็อกจะอ้างอิงข้อมูลจาก Android Developer หรือจะบอกว่าแปลเป็นภาษาไทยให้ฟังก็ได้ แต่เนื้อหาไม่ได้เอามาแปลทั้งหมดนะ จะเปลียนแปลงตามความเหมาะสมแทน


Supporting Multiple Screens
การรองรับหน้าจอที่หลากหลาย

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


Screen size
        ขนาดความกว้างและยาวของหน้าจอบนอุปกรณ์แอนดรอยด์ ส่วนมากจะวัดกันเป็นนิ้ว เช่น 2.4", 3.5", 4.5", 5", 7" หรือ 10.1" เป็นต้น สำหรับในแอนดรอยด์จะแบ่งขนาดหน้าจอออกเป็น 4 ขนาด คือ Small, Normal, Large และ Extra Large โดยรายละเอียดเบื้องลึกศึกษาได้จาก [Android Design] ว่าด้วยเรื่อง Size และ Density ของหน้าจอ


Screen Density
        ความหนาแน่นของหน้าจอซึ่งหมายถึงจำนวน Pixels ต่อหนึ่งหน่วยพื้นที่ โดยนิยมใช้หน่วยเป็น จุดต่อนิ้ว (dpi) อย่างเช่น 330 dpi ก็คือในหนึ่งนิ้วจะมี 330 จุดหรือ 300 Pixels ดังนั้นจอที่มีค่า dpi มาก ภาพที่ได้ก็จะคมชัดมากขึ้น สำหรับในแอนดรอยด์จะแบ่งความหนาแน่นของหน้าจอออกเป็น 6 ระดับ
คือ Low, Medium, High, Extra High, Extra Extra High และ Extra Extra Extra High โดยรายละเอียดเบื้องลึกศึกษาได้จาก [Android Design] ว่าด้วยเรื่อง Size และ Density ของหน้าจอ

Orientation
        ทิศทางของหน้าจอที่สามารถเปลี่ยนเป็นแนวนอนและแนวตั้งได้ ซึ่งไม่ได้ถูกกำหนดแค่ตอนเริ่มใช้งานเท่านั้น แต่สามารถเปลี่ยนแปลงได้ตลอดเวลาที่ใช้งาน โดยจะเรียกทิศทางของหน้าจอเป็น Portrait และ Landscape

Resolution
        ความละเอียดของหน้าจอเป็นจำนวน Pixel ในความกว้างและความสูง ซึ่งเป็นปัจจัยหลักในการรองรับกับหน้าจอหลายขนาดอีกทั้งยังสัมพันธ์กับขนาดหน้าจอและความหนาแน่นของหน้าจออีกด้วย โดยส่วนมากจะมีอัตราส่วนระหว่างความกว้างและความสูงดังนี้ 4:3, 16:9 และ 16:10 แต่ก็มีขนาดอื่นๆเช่นกัน สำหรับในแอนดรอยด์จะกำหนดขนาดหน้าจอเป็นตัวเลขโดยตรง อย่างเช่น 480x320, 800x480, 1024x600 และ 1280x720 เป็นต้น

Density-independent pixel (dp)
        เป็น Pixel เสมือน ที่เกิดจากการคำนวณด้วยสูตร px = dp * (dpi / 160) อย่างเช่นหน้าจอขนาด 240 dpi ดังนั้น 1 dp ก็จะเท่ากับ 1.5 px โดยรายละเอียดเบื้องลึกศึกษาได้จาก [Android Design] แท้จริงแล้วหน่วย dp คืออะไร?


        สำหรับผู้ที่หลงเข้ามาอ่านที่อยากรู้ว่าอุปกรณ์แอนดรอยด์ของคุณ มีหน้าจอขนาดเท่าไรและความหนาแน่นเท่าไร ให้ดาวน์โหลด Check Screen [Google Play] ซึ่งเป็นแอพสำหรับเช็คขนาดหน้าจอที่เจ้าของบล็อกเขียนเอาไว้



        เพื่อให้แอพพลิเคชันทำงานได้อย่างเหมาะสม ควรใช้ Resource หลายๆขนาด โดยให้รองรับกับขนาดต่างๆ อย่างเช่น ถ้าแอพพลิเคชัน ต้องการใช้ Bitmap หนึ่งภาพ ก็ควรมีขนาดใหญ่หนึ่งภาพสำหรับหน้าจอ แบบ hdpi หนึ่งภาพ และ mdpi หนึ่งภาพ ldpi หนึ่งภาพ และ xhdpi ถ้าที่ต้องการให้รองรับกับอุปกรณ์แอนดรอยด์ที่ขนาดหน้าจอใหญ่มาก หรือจะกำหนดตาม Small, Normal, Large และ Extra Large ก็ได้ โดยที่เราไม่จำเป็นต้องกำหนดว่าหน้าจอขนาดใดให้ใช้ไฟล์ไหน เพราะแอนดรอยด์จะมีระบบจัดการดังกล่าวให้ เพียงแค่จัดเก็บไฟล์ ในชื่อเดียวกันในโฟลเดอร์ที่บอกขนาดต่างๆ แอพพลิเคชันก็จะใช้ภาพในโฟลเดอร์ตามขนาดของอุปกรณ์ที่ใช้ โดยศึกษาเรื่องนี้ได้จาก [Android Design] การทำงานของโฟลเดอร์ใน Resource [res]

        บางทีผู้ที่หลงเข้ามาอ่านอาจจะสงสัยว่า ทำไมต้องจัดการเรื่องขนาดของภาพด้วย จึงแนะนำให้ดูภาพประกอบเลยดีกว่า อันนี้ภาพตัวอย่างจาก Android Develop ที่แสดงให้เห็นความแตกต่างระหว่างภาพแรกที่ใช้ภาพเดียวกันในหน้าจอที่ความหนาแน่นต่างๆ และภาพที่สองเป็นใช้ภาพแบ่งตามความหนาแน่นของหน้าจอตามที่แยกไว้ ซึ่งจะเห็นว่า ภาพที่สองจะมีขนาดของภาพที่ไม่เปลี่ยนแปลงสามารถรองรับกับหน้าจอได้หลายขนาด





How to Support Multiple Screens
ทำอย่างไรถึงจะรองรับหน้าจอได้หลายขนาด?


        • ประกาศว่าแอพพลิเคชันรองรับหน้าจอขนาดใดๆบ้าง โดยประกาศใน AndroidManifest.xml สามารถดูเนื้อหาได้จาก [Android Code] Android Compatibility ซึ่งจะทำให้แอพพลิเคชันใช้กับขนาดหน้าจอที่กำหนดเท่านั้น

        • สร้าง Layout ที่แตกต่างกันสำหรับขนาดที่แตกต่างกัน โดยปกติแอนดรอยด์จะกำหนดขนาดแอพพลิเคชันให้เต็มหน้าจอ แต่ในบางครั้งหน้าจอที่ใหญ่กว่าอาจจะทำให้การแสดงผลผิดเพี้ยนได้ การสร้าง Layout สำหรับหน้าจอขนาดต่างๆขึ้นมาก็จะช่วยแก้ปัญหาดังกล่าวได้ดีเช่นกัน

        • ใช้ภาพ Bitmap ในขนาดต่างกันสำหรับขนาดหน้าจอที่แตกต่างกัน ในกรณีที่เราใช้ภาพเพียงภาพเดียวโดยภาพนั้นพอดีกับหน้าจอขนาด Normal แต่เมื่อแสดงผลในหน้าจอ Large หรือ Small ภาพดังกล่าวก็จะถูกขยายหรือย่อลง ทำให้ภาพนั้นแตก ดูไม่สวยงามจึงควรใช้ภาพที่มีขนาดตามขนาดหน้าจอต่างๆ โดยแบ่งตามขนาดหน้าจอหรือความหนาแน่นของหน้าจอก็ได้

        • ควรใช้ wrap_content, fill_parent หรือ ใช้หน่วย dp กำหนดขนาด โดย wrap_content จะเป็นการกำหนดขนาดให้พอดีกับวัตถุนั้นๆ ส่วน fill_parent จะเป็นการขยายขนาดให้เต็มพอดีกับหน้าจอ และ dp จะเหมาะกับการกำหนดขนาด ซึ่งจะช่วยให้ขนาดของวัตถุมีขนาดที่เหมาะสมกับหน้าจอขนาดต่างๆ

        • ไม่ควรกำหนดขนาดเป็น px จากที่กล่าวมาแล้วว่าอุปกรณ์แอนดรอยด์มีความละเอียดของหน้าจอที่แตกต่างกัน ดังนั้นการกำหนดขนาดเป็นหน่วย px จะทำให้ขนาดของวัตถุคงที่ จึงมีขนาดเล็กลงเมื่อดูในอุปกรณ์แอนดรอยด์ที่มีความละเอียดหน้าจอสูง

        • ไม่ควรใช้ AbsoluteLayout ถึงแม้ว่า Layout แบบนี้จะสะดวกในการกำหนดตำแหน่งที่แน่นอนก็ตาม แต่จะไม่มีความคล่องตัวกับหน้าจอหลายๆขนาด เพราะเนื่องจากกำหนดตำแหน่งตายตัวนั่นเอง ด้วยข้อจำกัดดังกล่าวจึงทำให้ AbsoluteLayout ถูกเลิกใช้กันตั้งแต่ Android 1.5 แล้ว แนะนำให้ใช้ RelativeLayout แทนสามารถกำหนดตำแหน่งโดยให้สัมพันธ์กับตำแหน่งของวัตถุรอบข้างแทน เช่น "to the right of" เป็นต้น

        • สร้างโฟลเดอร์เก็บ Resource ตามขนาดของหน้าจอ อันนี้กล่าวถึงไปแล้วก่อนหน้า จึงไม่ขออธิบายเพิ่มเติม



Specific Resources
การกำหนด Resources โดยเฉพาะ


        จากที่กล่าวถึงไปแล้วถึงข้อดีของการเก็บข้อมูลออกเป็นหลายๆขนาด ทีนี้จะอธิบายถึงวิธีการเก็บข้อมูลดังกล่าวให้แอนดรอยด์สามารถเรียกใช้ได้ถูกต้อง โดยมักจะใช้กับ drawable และ layout เท่านั้น ซึ่งปกติไฟล์ที่เกี่ยวกับ drawable จะถูกเก็บไว้ที่โฟลเดอร์ res/drawable และไฟล์ที่เกี่ยวกับ layout จะถูกเก็บไว้ที่ res/layout โดยการกำหนดแบบเจาะจงให้สร้างโฟลเดอร์ที่มีชื่อดังนี้

        * ในตัวอย่างนี้จะเป็นตัวอย่างที่ใช้กับโฟลเดอร์ layout ในกรณีที่ใช้กับโฟลเดอร์ drawable ก็เพียงแค่เปลี่ยนจาก layout เป็น drawable เท่านั้น

        res/layout/ สำหรับหน้าจอขนาด Normal และ Default
        res/layout-small/ สำหรับหน้าจอขนาด Small
        res/layout-normal/ สำหรับหน้าจอขนาด Normal
        res/layout-large/ สำหรับหน้าจอขนาด Large
        res/layout-xlarge/ สำหรับหน้าจอขนาด Extra Large

        res/layout-ldpi/ สำหรับหน้าจอ ldpi
        res/layout-mdpi/ สำหรับหน้าจอ mdpi
        res/layout-hdpi/ สำหรับหน้าจอ hdpi
        res/layout-xhdpi/ สำหรับหน้าจอ xhdpi

        res/layout-port/ สำหรับหน้าจอในแนวตั้ง
        res/layout-land/ สำหรับหน้าจอในแนวนอน

        ในกรณีที่ต้องการกำหนดทั้งหน้าจอ ldpi และเป็นแบบแนวนอน ก็ให้ตั้งชื่อโฟลเดอร์ดังนี้

        res/layout-port-ldpi/

        โดยจะเรียงลำดับดังนี้ Size > Orientation > Density ดังนั้นจึงไม่สามารถตั้งชื่อโฟลเดอร์เป็น res/layout-ldpi-port/ ได้และกรณีที่ต้องการกำหนดโฟลเดอร์สำหรับหน้าจอขนาด Large แบบ hdpi และมีแนวนอน ก็กำหนดเป็น res/layout-large-land-hdpi/ และนอกจากมียังมีอื่นๆเพิ่มเติมอีกด้วย สามารถดูได้จาก Android Developer - Providing Resources



Alternative drawables
ทางเลือกต่างๆสำหรับ Drawables


        ที่กล่าวมาทั้งหมดอาจจะฟังดูง่าย อย่างเช่นไฟล์รูปที่ต้องมีหลายขนาดเพื่อเก็บแยกไว้ให้เหมาะสมกับขนาดหน้าจอ แต่ปัญหาต่อมาก็คือ เราควรสร้างภาพดังกล่าว ขนาดเท่าไรบ้างละ? ดังนั้นในการสร้างภาพสำหรับใช้งานบนแอพพลิเคชันโดยรองรับกับขนาดหน้าจอต่างๆ ให้ศึกษาจากบทความนี้ [Android Design] เคล็ดไม่ลับกับภาพ Drawable Resource สำหรับรองรับหน้าจอหลายขนาด