เข้าใจการแปลง Android dp เป็น px: ใช้งาน dp, sp และ px ได้ครบทุก density
แปลง Android dp เป็น px และ sp เป็น px ได้ทันทีด้วย Android dp / sp / px Converter ฟรี ใช้สูตร px = dp × dpi / 160 ครบทุก density bucket ตั้งแต่ ldpi ถึง xxxhdpi
Table of Contents
ถ้าคุณเคยลอกค่าจากไฟล์ดีไซน์แล้วสงสัยว่าพอไปแสดงบนเครื่องจริงแล้วจะกลายเป็นกี่พิกเซล ขอบอกว่าคุณไม่ได้เป็นคนเดียว เพราะ Android ใช้หน่วยขนาด 3 แบบ ได้แก่ dp สำหรับ layout, sp สำหรับขนาดตัวอักษร และ px สำหรับพิกเซลจริงบนหน้าจอ โดยการแปลงระหว่างหน่วยเหล่านี้จะขึ้นอยู่กับความหนาแน่น (density) ของหน้าจอแต่ละเครื่อง เครื่องมือ Android dp / sp / px Converter ฟรี ช่วยขจัดปัญหาการเดา เพราะแค่พิมพ์ค่าเดียวก็จะเห็นผลลัพธ์แปลงครบทุก density bucket ตั้งแต่ ldpi จนถึง xxxhdpi ทันที
ตัวสูตรเองไม่ยาก มีบรรทัดเดียวคือ px = dp × dpi / 160 แต่การคูณหารด้วยมือวันละยี่สิบครั้งคือจุดที่ความผิดพลาดมักเกิดขึ้นเสมอ ไม่ว่าจะเป็นการเอา 48dp ไปคูณ 3 เพื่อใช้กับ xxhdpi หรือการเอาค่าวัดจาก Photoshop ไปหาร 2 เพื่อใช้กับ xhdpi ลื่นไถลเรื่องการปัดเศษหรือลืม bucket ใด bucket หนึ่งไปได้ง่าย ๆ โดยไม่รู้ตัว
บทความนี้จะพาไปดูว่าเครื่องมือนี้ทำงานอย่างไร สูตรดังกล่าวมาจากไหน และวิธีนำไปใช้ในงาน Android ประจำวัน ทั้งการแปลงสเปกจากดีไซเนอร์ การเตรียมขนาด launcher icon การรักษากฎปุ่มกดขั้นต่ำ 48dp และการดีบัก layout บนอุปกรณ์เฉพาะรุ่น
ทำไมต้องใช้ Android dp / sp / px Converter?
- ได้คำตอบครบ 6 bucket ในทันที พิมพ์ค่า dp, sp หรือ px เพียงค่าเดียว ตาราง density แบบเรียลไทม์จะอัปเดต ldpi (120), mdpi (160), hdpi (240), xhdpi (320), xxhdpi (480) และ xxxhdpi (640) พร้อมกันหมด ไม่ต้องหยิบเครื่องคิดเลข
- แปลงได้สองทาง แปลง dp เป็น px และ px กลับเป็น dp ได้ ซึ่งตรงกับสิ่งที่ต้องทำจริง ๆ ทั้งตอนแปลงไฟล์ดีไซน์เป็นโค้ด layout และตอนเช็กว่าหน้าจอที่เรนเดอร์แล้วควรวัดได้เท่าไร
- จัดการ sp แยกต่างหาก ขนาดตัวอักษรจะขยายตามค่าที่ผู้ใช้ตั้งไว้ในระบบ เครื่องมือจึงแยก sp ออกจาก dp ให้ชัดเจน ไม่หลอกคุณว่าสองหน่วยนี้ใช้แทนกันได้
- ใช้สูตรตรงตาม Android ทุกค่าคำนวณด้วย px = dp × dpi / 160 ซึ่งเป็นความสัมพันธ์เดียวกับที่ runtime ของ Android ใช้จริง ตัวเลขจึงตรงกับสิ่งที่เห็นใน Layout Inspector
- รันในเบราว์เซอร์ ไม่ต้องติดตั้ง ไม่ต้องสมัครสมาชิก เปิดหน้าเว็บแล้วเริ่มแปลงได้ทันที แม้จะเป็นเครื่องที่ใช้รีวิวโค้ดอยู่ก็ตาม
- ลดบั๊กเรื่อง density เมื่อเห็นค่า px ของทุก bucket เรียงกันในหน้าเดียว คุณจะเห็นทันทีเลยว่าสเปกที่ดูดีบน xxhdpi จะถูกบีบจนแบนราบบน ldpi หรือเปล่า
ฟีเจอร์หลัก
| ฟีเจอร์ | สิ่งที่ทำ |
|---|---|
| แปลง dp ↔ px | เปลี่ยนหน่วย dp เป็นพิกเซลจริงและย้อนกลับได้ ที่ density ของ bucket ใดก็ได้ |
| แปลง sp ↔ px | แปลงขนาดตัวอักษรแบบ sp เป็นพิกเซล โดยแยกการสเกลของตัวอักษรออกจาก layout |
| ครบทุก density bucket | รองรับ ldpi (120), mdpi (160), hdpi (240), xhdpi (320), xxhdpi (480) และ xxxhdpi (640) |
| สูตร px = dp × dpi / 160 | ใช้สูตร density ทางการของ Android ผลลัพธ์จึงตรงกับที่แสดงบนเครื่องจริง |
| ตาราง density เรียลไทม์ | แสดงค่าที่กรอกแปลงเป็นทุก bucket พร้อมกัน เปรียบเทียบกันได้ในพริบตา |
| ทำงานในเบราว์เซอร์ | รันทั้งหมดในเบราว์เซอร์ ไม่ต้องติดตั้งอะไร ข้อมูลไม่ออกจากเครื่องของคุณ |
จุดที่น่าสนใจเพิ่มเติมมีดังนี้:
- เพราะผลลัพธ์แสดงทุก bucket พร้อมกัน คุณจึงเช็กเซ็ต asset ทั้งชุดได้ในแวบเดียว เช่น ปุ่มขนาด 48dp จะกลายเป็น 48, 72, 96, 144 หรือ 192 px ขึ้นอยู่กับแต่ละ bucket
- การแปลงสองทางเจ๋งมากตอนรีวิวโค้ด ลองวัดค่า px จากภาพหน้าจอแล้ววางเข้าไป คุณจะรู้ทันทีว่า layout ควรประกาศค่า dp เท่าไร
- การแยก sp ออกจาก dp อย่างชัดเจนเปรียบเสมือนเกราะป้องกันที่เงียบ ๆ ที่คอยเตือนใจว่าตัวอักษรกับโครงสร้าง layout ใช้กฎการสเกลที่แตกต่างกัน
วิธีใช้งาน Android dp / sp / px Converter
- เปิดเครื่องมือ เข้าไปที่หน้า Android dp / sp / px Converter โหลดไวทันทีในเบราว์เซอร์สมัยใหม่ ไม่ต้องสมัครอะไรทั้งสิ้น
- กรอกค่าที่ต้องการแปลง พิมพ์ตัวเลขที่ต้องการลงในช่องกรอก เช่น 48
- เลือกหน่วย ระบุให้ชัดว่าค่านั้นเป็น dp, sp หรือ px เพื่อให้เครื่องมือคำนวณตามทิศทางการสเกลที่ถูกต้อง
- อ่านตาราง density เรียลไทม์ เครื่องมือจะแสดงค่าเทียบเท่าของ ldpi, mdpi, hdpi, xhdpi, xxhdpi และ xxxhdpi ขึ้นมาทันที เช่น 48dp จะแสดงผลเป็น 48 px บน mdpi และ 144 px บน xxhdpi
- นำผลลัพธ์ไปใช้งาน คัดลอกค่า px ไปวางแผน export รูปภาพ หรือค่า dp ไปใส่ใน layout XML แล้วทำงานต่อได้เลย ไม่มีการบันทึกหรือส่งข้อมูลไปไหนทั้งสิ้น
Density Buckets และสูตรแปลง dp
ฮาร์ดแวร์ Android มีความหนาแน่นพิกเซลที่หลากหลายมาก ตั้งแต่มือถือรุ่นประหยัดที่ราว 200 dpi ไปจนถึงรุ่นเรือธงที่แซง 500 dpi ไปแล้ว ถ้าเราเขียน layout ด้วยค่า px ดิบ ๆ ปุ่มที่ดูเหมาะสมบนเครื่องหนึ่งอาจกลายเป็นจิ๋วบนอีกเครื่องหนึ่งทันที ทางออกของ Google คือหน่วย density-independent pixel (dp) ซึ่งเป็นหน่วยเสมือนที่ยึดจุดอ้างอิงไว้ที่ baseline mdpi 160 dpi กล่าวคือ 1dp เท่ากับ 1px บนหน้าจอ 160 dpi และค่าอื่น ๆ ทั้งหมดสเกลต่อจากจุดนี้ ความสัมพันธ์ทั้งหมดสรุปได้เป็น:
px = dp × (dpi / 160)
ดังนั้นปุ่ม 48dp จะแสดงผลเป็น 48 px บน mdpi, 96 px บน xhdpi และ 192 px บน xxxhdpi ซึ่งก็คือขนาดทางกายภาพที่เท่ากันบนทุกหน้าจอนั่นเอง ถ้าใช้สูตรย้อนกลับ dp = px × 160 / dpi คุณก็จะแปลงค่าที่วัดจากภาพหน้าจอกลับเป็นหน่วย layout ได้
เนื่องจากอุปกรณ์จริงมักกระจุกตัวอยู่รอบค่า density มาตรฐาน Android จึงจัดกลุ่มพวกมันเป็น 6 bucket ทางการ โดยแต่ละ bucket มี scale factor คงที่:
| Bucket | Density | Scale factor | 48dp เป็น px |
|---|---|---|---|
| ldpi | 120 dpi | 0.75x | 36 px |
| mdpi | 160 dpi | 1x | 48 px |
| hdpi | 240 dpi | 1.5x | 72 px |
| xhdpi | 320 dpi | 2x | 96 px |
| xxhdpi | 480 dpi | 3x | 144 px |
| xxxhdpi | 640 dpi | 4x | 192 px |
แล้วกรณีไหนที่ค่า px ดิบยังเป็นตัวเลือกที่ถูกต้อง? มีอยู่จริงครับ เช่น เส้นแบ่งบาง ๆ ขนาด 1 px ที่คุณต้องการให้หนาแค่หนึ่งพิกเซลกายภาพพอดี, การวาดบน canvas ที่จำเป็นต้องใช้พิกัดพิกเซลจริง หรือการวาง overlay ให้ตรงกับ bitmap นอกจากกรณีพิเศษพวกนี้แล้ว การเขียน px ตรง ๆ ลงใน layout แทบจะทุกครั้งคือบั๊กที่รอวันเครื่องที่ density สูงกว่ามาเจอะ
ตัวอักษรยังมีกฎเพิ่มอีกข้อ sp (scale-independent pixels) ทำงานเหมือน dp แต่จะถูกคูณเพิ่มอีกชั้นด้วยค่า font-size ที่ผู้ใช้ตั้งไว้ ทำให้คนที่ตั้งขนาดตัวอักษรระบบเป็นแบบ Large จะได้ป้ายข้อความที่ใหญ่ขึ้นโดยที่โครงสร้าง layout ไม่เปลี่ยน นั่นคือเหตุผลที่ทุกขนาดตัวอักษรใน Android ควรประกาศเป็น sp เสมอ ไม่ใช่ dp
กรณีใช้งานจริง
แปลงสเปกจาก Photoshop ให้เป็น dp
ดีไซเนอร์ UI ส่วนใหญ่ทำ mockup ที่สเกล 2x ซึ่งตรงกับ bucket xhdpi พอดี การ์ดที่วัดได้ 640 px ในไฟล์ คือ 320dp ในโค้ด และระยะห่าง 16 px คือ 8dp แค่วางค่า px ลงในตัวแปลง แล้วอ่านคอลัมน์ dp ออกมา layout XML ของคุณก็จะตรงกับดีไซน์โดยไม่ต้องหารด้วยมือแม้แต่ครั้งเดียว
เตรียมขนาด launcher icon สำหรับทุก bucket
สเปก launcher icon เริ่มจาก baseline 48dp ซึ่งจะกลายเป็น 48 px บน mdpi, 72 px บน hdpi, 96 px บน xhdpi, 144 px บน xxhdpi และ 192 px บน xxxhdpi export ทั้งชุดครั้งเดียว แล้วใช้ตาราง density ของตัวแปลงตรวจสอบขนาดของแต่ละไฟล์ก่อนส่งของขึ้น store
ตรวจสอบ touch target ขั้นต่ำ 48dp
Material Design กำหนดว่าองค์ประกอบที่กดได้ต้องกว้างอย่างน้อย 48dp หรือราว 9 มิลลิเมตร เพื่อให้นิ้วแตะลงไปตรงจุดเสมอ ถ้าสเปกระบุความสูงแถวไว้แค่ 32dp ให้คอมเมนต์จับผิดทันที ตัวแปลงจะบอกได้ทันทีว่าค่านั้นกลายเป็นกี่พิกเซลในแต่ละ bucket ซึ่งช่วยให้อธิบายปัญหาในที่ประชุมรีวิวด้วยตัวเลขที่จับต้องได้
ดีบัก layout บนอุปกรณ์เฉพาะรุ่น
Log และ Layout Inspector รายงานค่าเป็น px แต่ XML ของคุณประกาศเป็น dp view ที่วัดได้ 144 px บน emulator xxhdpi คือ 48dp พอดี ถือว่าถูกต้อง แต่ค่า 144 px เดียวกันบนเครื่อง xhdpi จะเท่ากับ 72dp แปลว่ามีบางอย่างอื่นไปเปลี่ยนขนาดของมัน การแปลงสองทางช่วยให้จับความไม่ตรงกันแบบนี้เห็นได้ในไม่กี่วินาที
แนวทางปฏิบัติที่ดี
- ใช้ dp กับ layout และ sp กับตัวอักษร dp ช่วยให้โครงสร้างสม่ำเสมอทุก density ส่วน sp จะเคารพค่า font-size ที่ผู้ใช้ตั้งไว้ด้วย เป็นการดูแล accessibility ไปในตัว
- อย่า hardcode px ลงใน layout สงวน px ไว้กับเส้น hairline และการคำนวณบน canvas เท่านั้น นอกนั้นมันจะพังเงียบ ๆ บน bucket อื่น
- รักษา touch target ไว้ที่ 48dp ขึ้นไป ต่ำกว่านั้นการแตะจะพลาดบ่อย โดยเฉพาะตอนผู้ใช้เดินอยู่ระหว่างทาง
- ทดสอบบนทั้ง bucket ต่ำและ bucket สูง emulator แบบ mdpi หรือ ldpi คู่กับเครื่อง xxxhdpi จะเผยปัญหาการสเกลที่หน้าจอ xhdpi เครื่องเดียวไม่มีทางโชว์ให้เห็น
- ใช้ vector drawables ให้มากที่สุด asset เดียวที่สเกลได้รองรับทุก bucket ทั้งย่อขนาด APK และตัดความจำเป็นในการคำนวณ px เกือบหมด
- ตรวจงาน handoff ด้วยหน่วย dp ไม่ใช่ px เมื่อดีไซเนอร์ส่งสเปกมา ให้แปลงค่า px เป็น dp ก่อน แล้วค่อยรีวิว layout เทียบกับตัวเลขชุดนั้น
หมดยุคแล้วที่จะต้องนั่งคิดเลข density ในหัว เปิด Android dp / sp / px Converter ขึ้นมา พิมพ์ค่าลงไป แล้วรับคำตอบของทุก bucket ในแวบเดียว ฟรี ไว ทำงานในเบราว์เซอร์ของคุณทันที
เครื่องมือที่เกี่ยวข้องที่คุณอาจสนใจ:
- Unit Converter — แปลงหน่วยความยาว น้ำหนัก อุณหภูมิ และอื่น ๆ อีกมากมาย
- Density Converter — แปลงค่าระหว่างความหนาแน่นหน้าจอสำหรับงานข้ามแพลตฟอร์ม
- CSS Logical Properties Converter — สลับ CSS ระหว่าง property แบบทิศทางกายภาพกับแบบ logical
ขอให้สนุกกับการแปลงหน่วยทุกครั้ง!
คำถามที่พบบ่อย
ถ: dp กับ px ใน Android ต่างกันอย่างไร? ตอบ: px คือพิกเซลกายภาพจริงบนหน้าจอ ส่วน dp คือหน่วยเสมือนแบบ density-independent ที่นิยามให้ 1dp เท่ากับ 1px บนหน้าจอ 160 dpi (mdpi) บนหน้าจอที่หนาแน่นกว่า ค่า dp เดิมจะกลายเป็น px มากขึ้นตามสูตร px = dp × dpi / 160 ซึ่งทำให้องค์ประกอบ UI มีขนาดทางกายภาพเท่ากันบนทุกอุปกรณ์
ถ: 48dp เท่ากับกี่พิกเซล? ตอบ: ขึ้นอยู่กับ bucket คือ 36 px บน ldpi, 48 px บน mdpi, 72 px บน hdpi, 96 px บน xhdpi, 144 px บน xxhdpi และ 192 px บน xxxhdpi ตาราง density แบบเรียลไทม์ของตัวแปลงจะแสดงทั้งหกค่าพร้อมกัน คุณจึงไม่ต้องเดาอีกเลย
ถ: ทำไมขนาดตัวอักษรควรใช้ sp แทน dp? ตอบ: เพราะ sp จะเคารพค่า font-size ที่ผู้ใช้ตั้งไว้ทั้งระบบ นอกเหนือจาก density ของหน้าจอ ทำให้ผู้ที่ชอบตัวอักษรใหญ่ได้ป้ายข้อความที่ใหญ่ขึ้นจริง ส่วน dp ดูแลแค่เรื่อง density อย่างเดียว ตัวอักษรที่กำหนดด้วย dp จะเมินค่า accessibility ของผู้ใช้และอาจเล็กจนอ่านไม่ออกสำหรับบางคน
ถ: ควรออกแบบ mockup ที่ density bucket ไหน? ตอบ: ทีมส่วนใหญ่นิยมออกแบบที่สเกล 2x ซึ่งตรงกับ bucket xhdpi (320 dpi) เพราะเอาค่า px มาหารสองก็ได้ dp ทันที ไม่ว่าจะเลือกสเกลไหน ให้ใช้สเกลเดียวกันทั้งโปรเจกต์เพื่อความสม่ำเสมอ แล้วปล่อยให้ตัวแปลงช่วยแปลงค่าไปเป็นทุก bucket ที่เหลือ