สร้างภาพง่ายๆจาก XML ด้วย Shape Drawable

โดยปกติเวลาสร้างแอปขึ้นมาซักตัวหนึ่ง ก็จะต้องมีการใช้รูปภาพใน UI กันอยู่แล้ว แต่รู้หรือไม่ว่าบนแอนดรอยด์นั้นสามารถใช้สิ่งที่เรียกว่า Shape Drawable เพื่อลดการใช้ไฟล์ภาพ​ ซึ่งจะช่วยให้แอปมีขนาดเล็กลงได้ด้วยนะ

Shape Drawable

เป็นหนึ่งในความสามารถของแอนดรอยด์ที่ทำให้นักพัฒนาสามารถสร้างรูปทรงง่ายๆได้ด้วย XML เพื่อใช้แทนไฟล์รูป โดยไฟล์ของ Shape Drawable ก็จะเก็บไว้ใน Drawable Resource เหมือนกับไฟล์ภาพทั่วๆไป (หรือที่เรียกในแอนดรอยด์ว่า Bitmap Drawable)

ซึ่ง Shape Drawable จะเหมาะกับภาพที่มีรูปทรงง่ายๆ และไม่ต้องการใช้เป็นไฟล์ภาพที่ต้องแยกตามขนาดหน้าจอ เพราะ Shape Drawable นั้นจะแสดงรูปแบบเดียวกับ Vector จึงไม่ต้องกังวลว่าจะเจอปัญหาภาพแตกเลย

และนอกจากนี้ Shape Drawable ยังปรับขนาดตาม View โดยอัตโนมัติ จึงไม่ต้องห่วงว่าภาพจาก Shape Drawable จะเบี้ยวหรือไม่สมสัดส่วนเหมือนการใช้ไฟล์ภาพ

จึงทำให้ Shape Drawable เหมาะกับการสร้างพื้นหลังของ View ต่างๆ อย่างเช่น Button หรือ Edit Text เป็นอย่างมาก

มาเริ่มสร้าง Shape Drawable กัน

ผู้ที่หลงเข้ามาอ่านสามารถสร้าง Shape Drawable ไว้ใน res/drawable ได้เลย เพราะไม่จำเป็นต้องสร้างแยกตามขนาดหน้าจอ

โดยคลิกขวาที่ drawable แล้วเลือก New > Drawable resource file ได้เลย

กำหนดชื่อไฟล์ได้ตามใจชอบ ส่วน Root element ให้กำหนดเป็น shape

เท่านี้ก็จะได้ไฟล์ Shape Drawable แล้ว~

ให้ลองเพิ่มคำสั่งเข้าไปดังนี้

<!-- shape_button_background_green.xml -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#c3ce46" />
</shape>

การสร้าง Shape Drawable จะคล้ายกับการสร้าง Layout ตรงที่สามารถดู Preview ระหว่างแก้ไข XML ได้ทันที

แต่การ Preview ในนี้จะเห็นแค่รูปทรงเดียวเท่านั้น ดังนั้นอาจจะต้องแปะลงใน View ก่อน แล้วค่อยดู Layout Preview แทน ถึงจะเห็นรูปร่างของ Shape Drawable ตามขนาดที่ต้องการ

Shape Drawable มีแบบไหนบ้าง

รูปร่างต่างๆที่สามารถสร้างด้วย Shape Drawable ได้ จะมีทั้งหมด 4 แบบด้วยกัน ดังนี้

ซึ่งทั้ง 4 แบบนี้จะมีการกำหนดค่าที่แตกต่างกันนิดหน่อย แต่ส่วนใหญ่ก็เหมือนๆกันน่ะแหละ

Corners

เป็นการกำหนดความโค้งของมุม Shape โดยปกติแล้วจะอยู่ในแท็กของ Shape ดังนี้

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:radius="dimension" />
</shape>

โดยการกำหนดขนาดของ Corner Radius สามารถกำหนดด้วย Dimension Unit อย่าง dp ได้เลย

หรือถ้าต้องการกำหนด Corner Radius แยกทั้ง 4 ด้าน ก็สามารถเปลี่ยนไปใช้ Attribute แบบนี้ก็ได้

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:bottomLeftRadius="dimension"
        android:bottomRightRadius="dimension"
        android:topLeftRadius="dimension"
        android:topRightRadius="dimension" />
</shape>

Gradient

เป็นการไล่เฉดสีบนพื้นผิวของภาพ

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:angle="float"
        android:centerColor="color"
        android:centerX="float"
        android:centerY="float"
        android:endColor="color"
        android:gradientRadius="dimension"
        android:startColor="color"
        android:type="linear|radial|sweep" />
</shape>

angle คือมุมทิศทางของ Gradient โดยกำหนดเป็นตัวเลข -270 ถึง 270 ได้เลย ดังตัวอย่างนี้

การกำหนดค่าสีจะมีทั้งหมด 3 ค่าด้วยกัน คือ startColor, centerColor และ endColor ซึ่งก็คือสีที่ต้องการกำหนดใน Gradient เรียงลำดับจากซ้ายไปขวา โดยกำหนดค่าสีเป็นแบบ #RRGGBB หรือ #AARRGGBB

ต่อไปเป็น type ที่เอาไว้กำหนดรูปแบบของ Gradient โดยจะมีรูปแบบของ Gradient ทั้งหมด 3 รูปแบบด้วยกัน คือ

Linear ไล่เฉดแนวยาว
Radial ไล่เฉดวงกลมจากจุดศูนย์กลาง
Sweep เป็นการไล่เฉดสีหมุนเป็นวงกลม

ต่อไปเป็น gradientRadius ที่เอาไว้กำหนดรัศมีของเส้น Gradient โดยกำหนดเป็นตัวเลขได้เลย​ สามารถกำหนดเป็น % ก็ได้ หรือจะกำหนดเป็นหน่วย DP ก็ได้เช่นกัน (ถ้าไม่ใส่ %)

ต่อไปเป็น centerX และ centerY เป็นการกำหนดจุดเริ่มต้นของ startColor ใส่ค่าเป็น % ก็ได้ 0% ถึง 100% ถ้ามากกว่านั้นก็จะล้นออกไปจากตัววัตถุแทน หรือจะใส่ 0 ถึง 1 ก็มีค่าเหมือนกับ 0% ถึง 100% เช่นกัน

โดยจะใช้ได้กับรูปแบบ Radial และ Sweep เท่านั้น ซึ่งการใช้กับ Radial จะต้องกำหนด gradientRadius ด้วย ส่วน Sweep นั้นไม่จำเป็นต้องกำหนดแต่อย่างใด

Padding

คือค่า Padding เหมือนกับตอนจัด Layout นั่นแหละ แต่สามารถกำหนดเตรียมไว้ตั้งแต่ใน Shape Drawable ได้เลย

Size

กำหนดขนาดของ Shape ที่สร้างขึ้น จะกำหนดหรือไม่ก็ได้ เพราะถ้าไม่กำหนดก็จะอิงกับขนาดของ View ที่ใช้งานแทน

Solid

เป็นการกำหนดสีของ Shape

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <solid android:color="color" />
</shape>

ถ้ากำหนดพร้อมกับ Gradient ก็จะใช้ Gradient แทน

สำหรับ color ก็คือค่าสีในรูปของ #RRGGBB หรือ #AARRGGBB นั่นเอง

Stroke

เป็นการกำหนดเส้นขอบของ Shape นั้นๆ ไม่มีผลกับ Shape แบบ Line

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <stroke
        android:width="dimension"
        android:color="color"
        android:dashWidth="dimension"
        android:dashGap="dimension" />
</shape>

width คือความหนาของเส้นของ แนะนำให้กำหนดเป็นหน่วย dp และ color คือสีของเส้นขอบ

ส่วน dashWidht กับ dashGap ขออธิบายคู่กันเลย เพราะใช้คู่กัน

Dash เป็นการลากเส้นประ โดยที่ dashWidth คือระยะของเส้นขีด และ dashGap เป็นระยะที่จะเว้นว่าง โดยจะสลับกันแบบนี้อัตโนมัติ แนะนำให้กำหนดค่าทั้งสองนี้ในหน่วย dp

นอกเหนือจากนี้ เจ้าของบล็อกไม่ได้พูดถึง เพราะว่าไม่ค่อยจำเป็นซักเท่าไร ไปกำหนดที่ View Attribute โดยตรงเลยดีกว่า

เพิ่มเติม - การกำหนด Shape แบบ Ring

ทีนี้ขอพูดถึง Shape แบบ Ring หน่อย อันนี้จะพิเศษนิดนึง ตรงที่ใน Attribute ของ Shape จะต้องกำหนดเพิ่มอีกสามอย่างคือ innerRadius, thickness และ useLevel

ซึ่ง innerRadius และ thickness ให้กำหนดเป็น dp ส่วน useLevel ให้กำหนดเป็น False (ขี้เกียจอธิบาย)

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:innerRadius="60dp"
    android:shape="ring"
    android:thickness="10dp"
    android:useLevel="false">
    <solid android:color="#ff4081" />
</shape>

ถึงเวลาสนุกแล้ว

เพราะนักพัฒนาสามารถจับคำสั่งต่างๆเหล่านี้มาผสมผสานได้ตามใจชอบ เพื่อให้ออกมาเป็นรูปแบบที่ต้องการ

สรุป

Shape Drawable เป็นหนึ่งในความสามารถของแอนดรอยด์ที่จะช่วยให้นักพัฒนาสามารถสร้าง Shape ในรูปแบบง่ายๆเพื่อใช้งานในแอปฯได้ โดยไม่ต้องมานั่งทำภาพเป็นไฟล์ JPG หรือ PNG เสมอไป

ซึ่งจุดเด่นหลักๆของ Shape Drawable คือไม่ต้องกลัวภาพแตก เพราะจะถูกวาดใหม่ทุกครั้งเมื่อแสดงผลบน View ต่างๆ และตัวไฟล์ XML ของ Shape Drawable ก็มีขนาดเล็ก จงทำให้ลดขนาดของไฟล์ APK ได้พอสมควรเลย

ดังนั้นทางที่ดีเวลาออกแบบแอปก็แนะนำว่าควรออกแบบรูปภาพที่ไม่ซับซ้อนมากนัก ควรมีลักษณะ Flat หรือจะอิงตาม Material Design เลยก็ได้ เพื่อที่ว่าจะได้ไม่ต้องเสียเวลาทำภาพให้กับหน้าจอแต่ละแบบ