05 สิงหาคม 2556

[Android Design] การทำงานของโฟลเดอร์ใน Resource [res]


        ห่างหายไปนานกับบทความดีไซน์ เพราะที่ผ่านมา มัวแต่ทำเรื่องโค๊ด ก็เลยขอเขียนเรื่องดีไซน์กันบ้างโดยเป็นเรื่องโฟลเดอร์ Resource ก่อน เพื่อปูทางไปสู่เนื้อหาของการออกแบบหน้าจอให้รองรับกับหลายๆขนาด


        ผู้ที่หลงเข้ามาอ่านทุกคนก็คงจะคุ้นเคยกับโฟลเดอร์นี้ดี แต่ก็ยังมีหลายคนที่ไม่เข้าใจการทำงานของโฟลเดอร์นี้ว่าทำไมต้องมีหลายโฟลเดอร์ทั้งๆที่ชื่อนำหน้าเหมือนกัน

        โฟลเดอร์ที่อยู่ภายใน res จะแยกข้อมูลตามคุณสมบัติเครื่องได้ อย่างเช่น ขนาดหน้าจอ ความละเอียดหน้าจอ ภาษา เป็นต้น โดยเจ้าของบล็อกจะอธิบายด้วยกัน 3 โฟลเดอร์ คือ drawable, layout และ values เท่านั้น เพราะอันอื่นไม่จำเป็น


Drawable

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

        ขนาดหน้าจอ (Screen Size) : small, normal, large และ xlarge

        ความหนาแน่น (Screen Density) : ldpi, mdpi, tvdpi, hdpi, xhdpi, xxhdpi และ xxxhdpi

        ทิศทางของจอ (Orientation) : Landscape และ Portrait

        จริงๆมี Resolution, Aspect Ratio และ DP ด้วย แต่ไม่ค่อยได้ใช้ก็เลยข้ามไปละกัน สำหรับเนื้อหาในเรื่องของขนาดหน้าจอสามารถศึกษาเพิ่มได้จาก [Android Design] ว่าด้วยเรื่อง Size และ Density ของหน้าจอ


        สมมติว่าเจ้าของบล็อกมีภาพ 2 ภาพ สำหรับจอ mdpi และ xhdpi



        เจ้าของบล็อกก็ต้องแยกไฟล์ทั้งสองไว้ในโฟลเดอร์ res ดังนี้


        ** เน้นย้ำว่าทั้งสองไฟล์ต้องมีชื่อไฟล์เหมือนกัน **


        สมมติว่าจะแยกไฟล์ภาพตามขนาดจอ (small, normal, large และ xlarge)



        เวลาที่ใช้เครื่องไหน ภาพในโฟลเดอร์ drawable ก็จะอิงจากขนาดหน้าจอ



        สมมติว่าแอปพลิเคชันที่สร้างจะรองรับทั้งแนวตั้งและแนวนอน โดยต้องการให้ภาพที่แสดงในแนวตั้งและแนวนอนต่างกัน  ในการกำหนดชื่อโฟลเดอร์จะย่อคำเป็น port กับ land แทน



        แล้วถ้าต้องการแยกภาพสำหรับขนาดหน้าจอและความหนาแน่นที่ต่างกันล่ะ? ก่อนอื่นให้ดูการตั้งชื่อโฟลเดอร์ drawable ก่อน โดยจะเรียงตามลำดับดังนี้ 

                drawable - size orientation density

        ไม่จำเป็นต้องระบุให้ครบทั้งสามอย่างก็ได้ แต่ต้องเรียงแบบนี้เท่านั้น



        สมมติว่าต้องการทำ 

                [normal, land, mdpi] 

                [normal, port, mdpi] 

                [normal, hdpi] 

                [normal, xhdpi] 

                [large, mdpi] 

                [large, land, tvdpi] 

                [xlarge, port, mdpi] 

                [xlarge, port, tvdpi] 

                [xlarge, port, hdpi] 

        จะได้ดังนี้



        ในกรณีที่พิมผิดหรือเรียงลำดับผิดหรือตั้งชื่อไม่ตรง เดี๋ยวก็ขึ้นแบบนี้ให้เห็น


        แล้วโฟลเดอร์ที่ชื่อ drawable เฉยๆละ? หมายความว่ายังไง? สำหรับ drawable ก็เปรียบเสมือนโฟลเดอร์เริ่มต้นหรือ Default  ในกรณีเครื่องที่ใช้มีคุณสมบัติไม่ตรงกับโฟลเดอร์ที่สร้างไว้



        แต่การตั้งชื่อโฟลเดอร์แบบนี้ก็ไม่ได้ถือว่าเด็ดขาดนัก เพราะระบบจะหยืดหยุ่นให้เล็กน้อย ดังตัวอย่างนี้


        จะเห็นว่าสถานะเครื่องในตอนนั้นเป็น normal-land-xhdpi แต่เนื่องจากโฟลเดอร์ normal-port-xhdpi ได้กำหนดเป็น port ระบบจะมองหาโฟลเดอร์ที่ไม่ได้กำหนด Orienation เพื่อใช้แทน ถึงแม้ว่าเงื่อนไขบางอย่างจะไม่ตรงก็ตาม ดังตัวอย่างที่เป็น hdpi

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


Layout

        จบเรื่องโฟลเดอร์ drawable ก็มาต่อกันที่โฟลเดอร์ layout โดยเจ้าของบล็อกจะไม่ค่อยยุ่งอะไรมากกับโฟลเดอร์นี้ เพราะจะไปจัดการในโฟลเดอร์อื่นแทน (พูดถึงในภายหลัง) สำหรับโฟลเดอร์ layout ก็แนะนำให้กำหนดคุณสมบัติ 2 อย่าง คือ short-width และ orientation สำหรับ short-width ให้ดูเพิ่มเติมใน [Android Design] ว่าด้วยเรื่อง Size และ Density ของหน้าจอ

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

        อย่างแรกเลยคือสร้างโฟลเดอร์โดยแยกตาม orientation



        ซึ่งเคยอธิบายไปแล้วในบทความเก่า เลยไม่อธิบายอะไรมาก [Android Design] Screen Rotation ทำอย่างไรให้รองรับกับการหมุนหน้าจอได้

        ต่อมาก็คือ short-width หรือด้านใดด้านหนึ่งของหน้าจอที่สั้นที่สุด


        ซึ่งค่านี้ล่ะที่จะเป็นตัวระบุได้ว่าเครื่องนั้นๆเป็น Phone หรือ Tablet โดยที่ต่ำกว่า 600dp จะเป็น Phone มากกว่า 600dp เป็น Tablet และแบ่งได้อีกว่ามากกว่า 600dp จะเป็น Tablet ขนาด Large (7 นิ้ว) แต่ถ้ามากกว่า 720dp จะเป็น Tablet ขนาด xlarge (พวก 10 นิ้ว)

        จึงนำค่าดังกล่าวมาใช้ประโยชน์ในการกำหนดโฟลเดอร์ layout ได้ เพื่อออกแบบ layout สำหรับ Phone, Tablet เล็กและ Tablet ใหญ่ได้ จึงเป็นที่มาของการสร้างแอปพลิเคชันตัวเดียวแต่รองรับได้ทั้งหมด


        จริงๆแล้วตัวเลขของ short-width จะกำหนดเป็นเท่าไรก็ได้ แต่นิยมใช้กันที่ 600 และ 720 เพื่อแยกประเภทของเครื่องเท่านั้น ในกรณีที่เครื่องเป็น Phone ก็จะตกไปอยู่ในโฟลเดอร์ layout โดยปริยาย

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


        จะเห็นว่าการตั้งชื่อโฟลเดอร์ layout จะเรียงลำดับตามนี้

                layout - sw - orientation

        เวลาสร้าง Layout ไม่แนะนำให้กำหนดค่า dp ลงไปตรงๆนะ จะให้เก็บค่าไว้ในโฟลเดอร์ values แล้วเรียกใช้ค่าจากในนั้นแทน เพื่อที่ว่าเวลาแก้ไขค่าตัวเลขของ Layout จะได้มาแก้ที่ไฟล์ xml ซึ่งจะดูได้สะดวกและง่ายกว่าดูในโฟลเดอร์ layout


Values

        สำหรับโฟลเดอร์ values ก็จะเอาไว้เก็บค่าต่างๆ ในรูปของไฟล์ xml อย่างเช่น ค่าที่ใช้กำหนดขนาดใน Layout หรือ String ที่เอาไว้เรียกใช้ โดยปกติเจ้าของบล็อกจะเก็บพวกค่าที่กำหนด Layout ไว้ในนี้ทั้งหมด ใน Layout ทุกไฟล์ที่มีก็จะอิงค่าที่กำหนดจากโฟลเดอร์นี้แทน รวมไปถึง String และ Style ที่กำหนดตายตัวไว้ แล้วเรียกใช้ได้เลย


        จะเห็นว่าโฟลเดอร์ values จะกำหนดค่า Android version ได้ด้วย ในภาพข้างบนนี้จะกำหนดเป็น v11 และ v14 ที่สร้างให้อัตโนมัติ 11 กับ 14 นี้ก็คือ API version นั่นเอง จะได้เป็น API 11 กับ API 14 โดยในสองโฟลเดอร์นี้และโฟลเดอร์ value จะมีไฟล์ styles.xml ที่เอาไว้กำหนด Style หรือ Theme ที่เป็นของหน้าแอปพลิเคชัน เพราะว่า Style นั้นทยอยเพิ่มเข้ามาในเวอร์ชันใหม่ๆแต่ละตัว จึงมีการกำหนดแยกได้ว่า เครื่องเป็นเวอร์ชันใดก็ให้ใช้ Style นั้นๆ แต่ Style ไม่ได้ใช้ ถ้าผู้ที่หลงเข้ามาอ่านออกแบบหน้าใหม่ทั้งหมด (จริงๆเอาไว้กำหนด Style อื่นๆได้หมด เช่น List View หรือ Spinner เป็นต้น)

        ทีนี้มาดูที่ไฟล์ string.xml ไฟล์นี้เอาไว้สร้าง String เตรียมทิ้งไว้ใช้งาน ข้อดีของการสร้างในนี้ก็คือเวลาเรียกใช้จะสั้นพอสมควร ในกรณีที่เก็บข้อความยาวๆไว้ในนี้ เวลาเรียกใช้ก็เรียกแค่ R.string.xxx โดยโฟลเดอร์ที่เก็บไฟล์ดังกล่าวควรเป็นโฟลเดอร์ที่กำหนดภาษาไว้ เช่น String สำหรับภาษาไทย หรือภาษาอังกฤษเป็นต้น ตรงจุดนี้จะขอข้ามไปเลย เพราะเคยพูดถึงแล้วในบทความเรื่อง [Android Design] Multiple Language การออกแบบให้รองรับหลายภาษา

        ทีนี้มาดูที่ dimen.xml ต่อ เพราะสำคัญกับการรองรับหน้าจอหลายขนาด โดยไฟล์นี้ให้เก็บไว้ในโฟลเดอร์ที่กำหนดขนาดหน้าจอเอาไว้ เหมือนกับการกำหนดในโฟลเดอร์ drawable เลยนั่นแหละ


        ภาพตัวอย่างที่ยกมาข้างต้น สมมติว่าสร้าง Layout แค่ทิศทางเดียว ใน dimens.xml แต่ละไฟล์ ก็จะเก็บค่าขนาดต่างๆของ Widget ใน Layout

        ตัวอย่างการใช้งาน string.xml กับ dimens.xml


        เวลาต้องการทดสอบดูว่าพอดีกับหน้าจอหลายๆขนาดหรือป่าว ให้ใช้วิธีนี้ [Android Dev Tips] Device Definitions ของเก่าเอามาทำใหม่ [SDK Tools 21 ขึ้นไป] เวลาทดสอบหน้าจอก็กดดูคร่าวๆในหน้า Layout ได้เลย

        จริงๆกะว่าจะไม่แจกไฟล์ตัวอย่างนะเพราะไม่มีโค๊ด แต่เห็นว่ามีตัวอย่างในตอนท้ายก็เลยแจกไปเลย จะได้เอาไปดูเป็นตัวอย่างว่าเจ้าของบล็อกทำยังไง เรื่องแบบนี้ก็ไม่ได้ตายตัวเหมือนเคยนะ เพราะว่าขึ้นอยู่กับแต่ละคนว่าจะใช้วิธีไหนในการจัดการกับหน้าจอให้รองรับได้หลายขนาด

        สำหรับผู้ที่หลงเข้ามาอ่านคนไหนที่ต้องการไฟล์ตัวอย่าง สามารถดาวน์โหลดตัวอย่างได้ที่ Resource Used Sample [Google Drive]




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

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