24 เมษายน 2557

[Android Design] Margin กับ Padding มีดีอย่างไร และต่างกันอย่างไร?


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


        สำหรับ Margin และ Padding จะเป็น Properties ที่มีอยู่ในการออกแบบ Layout สำหรับแอปพลิเคชัน เอาไว้กำหนดระยะห่างระหว่าง Widget ต่างๆบนจอ ซึ่งเป็นอีกหนึ่งหัวใจสำคัญของการจัดวาง Layout ในแอปพลิเคชัน

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

        สำหรับ Margin จะสามารถกำหนดค่าได้จาก Layout Parameters โดยกำหนดเป็นหน่วย dp


      หรือจะกำหนดแบบ XML ก็จะได้ดังนี้
android:layout_margin="10dp" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:layout_marginRight="10dp" android:layout_marginBottom="10dp" android:layout_marginStart="10dp" android:layout_marginEnd="10dp"


        ส่วน Padding จะสามารถกำหนดค่าได้จาก View โดยกำหนดเป็นหน่วย dp เช่นกัน


        หรือจะกำหนดแบบ XML ก็จะได้ดังนี้
android:padding="10dp" android:paddingLeft="10dp" android:paddingTop="10dp" android:paddingRight="10dp" android:paddingBottom="10dp" android:paddingStart="10dp" android:paddingEnd="10dp"


        สำหรับนิยาม Margin สำหรับการออกแบบ Layout ในความเห็นส่วนตัวของเจ้าของบล็อกคือการเว้นช่องว่างตรงขอบของ View โดยขยายออกไป ส่วน Padding คือการเว้นช่องว่างตรงขอบของ View โดยบีบเข้ามาภายในตัว View


        หรือพูดในอีกแง่หนึ่งก็คือ Margin จะเป็นการที่ View ดันขอบเขตออกไปรอบๆตัว ส่วน Padding บีบขอบเขตเข้ามาข้างในตัวมันเอง


        ยกตัวอย่างกับ Margin ก่อนละกัน สมมติว่าเจ้าของบล็อกวาง View ตัวหนึ่งไว้ใน Layout แล้วกำหนดให้ความกว้างกับความสูงเป็น match_parent ซึ่งโดยปกติ จะทำให้ View มีขนาดพอดีกับ Layout


        พอกำหนด Margin เข้าไปก็จะทำให้ View ขยายขอบเขตออกไปตามค่า Margin ในด้านต่างๆที่ได้กำหนดไว้ ในกรณีที่ Layout ยังขยายได้อยู่ View ก็จะมีขนาดเท่าเดิม และดันขอบของ Layout ให้ขยายขึ้นไปอีกตามที่กำหนด


        แต่ถ้า Layout ไม่สามารถขยายได้แล้ว มีขนาดสูงสุดที่จะขยายได้แล้ว (อาจจะอยู่ใน Layout อีกชั้นที่กำหนดขอบเขตไว้) Layout ก็จะไม่ขยายต่อไป แต่ตัว View จะโดนบีบให้เล็กลงไปโดยปริยาย และถ้า Content ใน View สามารถถูกบีบได้เช่น Text View ก็จะทำให้ Content ใน View นั้นๆโดนบีบด้วย ถ้ากำหนด Margin แล้วบีบ View ให้แคบลงมากเกินไป



        ต่อมาเป็น Padding บ้าง เจ้าของบล็อกจะสมมติว่า View เป็น wrap_content ทั้งความกว้างและความสูง แล้ว Layout มีความกว้างความสูงมากกว่า View อยู่ระดับนึงหรือจะเป็น match_parent ไปเลยก็ได้


        เมื่อเจ้าของบล็อกกำหนด Padding ให้กับ View ทั้งสี่ด้าน การ Padding ก็จะบีบ Content ของ View เข้ามา แต่ทว่าถ้า Content ไม่สามารถถูกบีบได้อีกก็จะทำให้ View ขยายตัวออกแทน เพื่อให้ Padding ตรงตามที่กำหนด


        หลักการเบื้องต้นของ Margin กับ Padding ก็จะมีประมาณนี้ ทีนี้มาดูกันต่อว่าการใช้งานในบางกรณีจะทำให้ Margin กับ Padding มีผลลัพธ์ออกมายังไงบ้างล่ะ?


        จากเดิมที่เจ้าของบล็อกบอกว่าถ้า Margin กำหนดเยอะ แล้ว Layout ขยายขนาดไม่ได้ มันจะไปบีบ Content ใน View ให้แคบลงแทน ก็จะยกตัวอย่างให้ดูว่ามันเป็นยังไง


        จากภาพข้างบนนี้เป็นตัวอย่างง่ายๆเลยของการวาง Text View ไว้ใน Layout ซักตัว โดยจัดให้ Text View อยู่ตรงกลางของ Layout

        สมมติว่าเป็น Relative Layout ก็จะจัด Layout ใน XML ดังนี้
<RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="[ข้อความยาวๆพอดีกับขอบ Layout]" /> </RelativeLayout>

        ถ้าเป็น Linear Layout ก็จะเป็นแบบนี้
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="[ข้อความยาวๆพอดีกับขอบ Layout]" /> </LinearLayout>

        แล้วเจ้าของบล็อกกำหนด Margin ให้กับ Text View ที่ฝั่งซ้ายและขวาเป็นระยะ 10dp
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="TextView" />

        ผลที่ได้คือ Text View จะดันขอบเขตออกไปทางด้านข้างซ้ายและขวา แต่ทว่าไม่สามารถดันให้ Layout ขยายได้อีกแล้ว เพราะว่า Layout มีความกว้างเป็น match_parent หรือก็คือความกว้างสูงสุดแล้ว จึงทำให้ Margin มีผลกับตัว Content ของ Text View แทน นั่นก็คือข้อความที่ใส่ไว้

         Text View ก็จะถูกบีบแคบเข้ามาแทน ส่งผลให้ข้อความที่อยู่ใน Text View ตัดคำขึ้นบรรทัดใหม่กลายเป็นสองบรรทัด แทนที่เดิมจะเป็นบรรทัดเดียว


        แต่ความซนยังไม่จบลงเพียงเท่านี้ เจ้าของบล็อกยังดันทุรังกำหนด Margin ของข้างบนและข้างล่างเพิ่มเข้าไปอีก เพื่อบีบ Text View โดยกำหนดระยะซัก 15dp
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="12dp" android:layout_marginBottom="12dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="TextView" />

        ผลที่ได้ก็คือ Text View ก็จะโดนบีบเข้าไปอีก เพื่อให้ Margin มีระยะตามที่กำหนด จึงส่งผลให้ข้อความใน Text View โดนกินพื้นที่หายไปบางส่วน หรือก็คือเริ่มสูญเสียพื้นที่ Content ไป



        ถ้าพิเรณกำหนดเยอะๆล่ะ?



        สาเหตุที่ Text View ถูกบีบจนหายไปก็จะมาจากการที่กำหนดความสูงเป็น wrap_content หรือ match_parent ซึ่งการกำหนดความสูงแบบนี้จะทำให้ View ไม่มีค่าตายตัว ทำให้ขนาดแปรเปลี่ยนไปตาม Parent หรือ Content ที่เปลี่ยนแปลงไป ดังนั้นถ้าลองกำหนดขนาดให้กับ Text View ดู

<TextView android:layout_width="wrap_content" android:layout_height="30dp" android:layout_marginTop="200dp" android:layout_marginBottom="200dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="TextView" />

        ก็จะพบว่า Layout จะให้ความสำคัญกับขนาดของ View มากกว่า Margin ทำให้ Text View ดังกล่าวมีความสูง 100dp ในขณะที่ 200dp จะไม่ทำให้ Text View โดนบีบแต่อย่างใดเลย ระยะ Margin ทำได้เท่าไรก็จะอยู่แค่นั้นทันที



        สำหรับ Padding ถ้ากำหนดค่าเยอะเกิน ก็จะไม่มีผลอะไรมากนัก เพราะมันจะไปดัน Layout ให้กว้างมากที่สุดเท่าที่ Layout นั้นๆทำได้


        ถ้าเจ้าของบล็อกกำหนด Padding จนสุดที่ Layout จะขยายได้ ก็จะไปกินพื้นที่ของ Content แทน






        ถึงจุดนี้ ผู้ที่หลงเข้ามาอ่านคงจะพอเข้าใจกับการทำงานของ Margin และ Padding บ้างแล้วล่ะมั้ง (ถ้าไม่เข้าใจก็วนกลับขึ้นไปอ่านใหม่ แล้วลองทำในโปรแกรมดูการทำงาน)


        ทีนี้มาเปลี่ยนมุมมองบ้างดีกว่า จากเดิมเจ้าของบล็อกใช้คำสั่ง Margin กับ Padding ให้กับ View ดังนั้นคราวนี้ลองมาเปลี่ยนเป็น Layout กันบ้าง โดยจะขอตีกรอบให้เห็นพื้นที่สมมติว่าเป็นหน้าจออุปกรณ์แอนดรอยด์เสียหน่อย


        เมื่อพิจารณาการกำหนด Margin หรือ Padding ที่ Layout แทน ก็จะได้ออกมาเป็นแบบนี้



        จะเห็นว่าหลักการเหมือนกันเป๊ะๆ แต่เปลี่ยนจาก View มาเป็นที่ Layout แทน ซึ่ง Content ในกรณีของ Layout ก็คือ View นั่นเอง โดยจะถือว่า Content ของ Layout ในตอนนี้คือ View เพราะว่ามันอยู่ข้างใน Layout ดังนั้นในเวลาที่กำหนด Margin หรือ Padding เยอะๆ View ก็จะโดนบีบแทนไปโดยปริยายนั่นเอง


        ทีนี้มาดูสรุปคร่าวๆของ Margin กับ Padding อีกเล็กน้อยซะหน่อยละกัน

        • กำหนด Padding ให้กับ Layout หรือ กำหนด Margin ให้กับ View ที่อยู่ใน Layout จะให้ผลลัพธ์เหมือนกัน ต่างกันที่ตำแหน่งของคำสั่ง

        กำหนด Padding ให้กับ Layout
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" android:paddingLeft="10dp" android:paddingRight="10dp" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="นอนหลับบ้างอะไรบ้าง" /> </LinearLayout>


        กำหนด Margin ให้กับ View
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:orientation="vertical" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:text="นอนหลับบ้างอะไรบ้าง" /> </LinearLayout>


        • ไม่จำเป็นต้องมี View แค่ตัวเดียว จะมีเท่าไรก็ได้ แต่ Layout จะมองเป็นกลุ่มก้อนเดียวกันในเวลาที่กำหนด Padding

        สมมติว่าเจ้าของบล็อกสร้าง Layout โดยมี View อยู่ข้างในเรียงกัน 3 ตัวดังนี้
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button1" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button2" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button3" /> </LinearLayout>

        ทีนี้เจ้าของบล็อกกำหนด Padding ให้กับ Layout เฉพาะฝั่งซ้ายและข้างบน
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="5dp" android:paddingTop="5dp" android:orientation="horizontal" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button1" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button2" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Button3" /> </LinearLayout>


        และถ้ากำหนดเยอะเกินก็จะเป็นเหมือนเดิม คือ Content (ในที่นี้ Content ของ Layout คือ View ทั้งสามตัว) ก็จะถูกบีบไปโดยปริยาย


        • อย่าลืมว่า Layout ก็สามารถซ้อนกันได้ เพราะงั้น Margin หรือ Padding ก็มีผลด้วยเช่นกัน ขึ้นอยู่กับว่ากำหนดคำสั่งให้กับ Layout อันไหน และสามารถกำหนด Margin หรือ Padding แยกย่อยลงไปได้ตามต้องการ

        โดยภาพตัวอย่างเจ้าของบล็อกจะเหลือขอบให้เห็นเล็กน้อย เพื่อให้รู้ว่า Layout ซ้อนกัน และใน Layout มี View อยู่ (ในความเป็นจริงมันจะทับกันพอดีจนไม่เห็น)


<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> </LinearLayout> </LinearLayout>

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

        เริ่มจากกำหนด Padding ให้กับ Layout ทั้ง 2 อันที่อยู่ใน Layout ก่อน จะกำหนด Margin ของ View ก็ได้เช่นกัน
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="5dp" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="5dp" android:paddingRight="5dp" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> </LinearLayout> </LinearLayout>

        จะเห็นว่ามี Layout ตัวนึงที่กำหนด Padding ทั้งสี่ด้าน แต่อีกตัวหนึ่งจะไม่กำหนดด้านที่ชิดกับ Layout อีกตัว เพราะไม่งั้นมันจะทำให้ View ทั้งสองฝั่งห่างกันจนเกินไป

        ทีนี้ก็กำหนด Margin ให้กับ View ที่อยู่ข้างใน เฉพาะตัวที่อยู่ข้างล่าง
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="5dp" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="View" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:padding="5dp" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="View" /> </LinearLayout> </LinearLayout>

        จากนั้นก็เพิ่ม Padding ให้กับ Layout ที่อยู่ข้างนอกสุด
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="5dp" android:orientation="horizontal" > <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:paddingTop="5dp" android:paddingBottom="5dp" android:paddingLeft="5dp" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="View" /> </LinearLayout> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:padding="5dp" > <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="View" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="5dp" android:text="View" /> </LinearLayout> </LinearLayout>


        เท่านี้ก็จะได้การจัดวาง View ที่มีช่องไฟระหว่าง View ด้วยกันแล้ว เมื่อสรุปการทำงานของ Margin กับ Padding ก็จะออกมาเป็นแบบนี้


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




        • ในการนำไปใช้งานจริงๆ มักจะใช้เพื่อให้เกิดช่องไฟระหว่าง View หรือ Layout เพื่อให้ดูสวยงามและลงตัว ดังนั้นควรออกแบบไว้ก่อนแล้วดูว่าตรงไหนควรใช้ Margin หรือ Padding

        ยกตัวอย่างเช่น แอปพลิเคชันที่มี Custom View บางอย่างที่มีลักษณะเป็น List สมมติว่าเป็น List View ละกัน โดยปกติมักจะมีหน้าตาเป็นแบบนี้


        จะเห็นว่า Content มีขนาดเต็มพอดี จึงทำให้เวลาใช้งานใน List View เกิดปัญหาว่า มันชิดกันมากเกินไปทำให้ดูไม่ค่อยสวยซักเท่าไร ดังนั้นทางที่ดีควรเพิ่ม Margin เข้าไปเพื่อให้เกิดช่องไฟระหว่าง Content เพื่อให้ผู้ใช้ดูได้สะดวกขึ้น (Content ที่เรียงกันเป็นพรึ่ดๆย่อมอ่านไม่สะดวกอยู่แล้ว)


        สำหรับความสูงของ Content จะเห็นว่ามันลดลง ซึ่งจริงๆไม่จำเป็นต้องลดลงเสมอไป เพราะถ้ากำหนดความสูงเป็น wrap_content มันก็จะดันขอบขยายออกไปแทน (แต่ในภาพลดขนาด Content มันทำง่ายกว่า ฮาๆ)


        หรือเมนูที่อยู่ชิดริมหน้าจอเพื่อให้ผู้ใช้กด ยกตัวอย่างเป็นปุ่มแชร์ไปยัง Social ต่างๆละกัน


        จะเห็นว่า View แต่ละอันชิดเกินไป Layout ก็ชิดกับ View จนเกินไป แถม Layout ก็อยู่ซะติดมุมเลย ดังนั้นลองทำช่องไฟระหว่าง View แล้วเขยิบ Layout ออกมาจากมุมเสียหน่อย จากนั้นก็ขยาย Layout ด้วย Padding เสียหน่อย




        สำหรับบางอย่างในเนื้อหานี้อาจจะไม่จำเป็นต้องใช้ Margin หรือ Padding เสมอไป อาจจะใช้การกำหนด Gravity ให้กับ Layout ก็ได้เช่นกัน แต่เนื่องจากบทความนี้พูดถึง Margin กับ Padding เป็นหลัก ก็เลยยกตัวอย่างเป็นการใช้งาน Margin กับ Padding เกือบทั้งหมด

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




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

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