สไตล์และธีมใน Android ช่วยให้คุณแยกรายละเอียดการออกแบบแอปออกจากโครงสร้างและลักษณะการทํางานของ UI ได้ ซึ่งคล้ายกับสไตล์ชีตในการออกแบบเว็บ
style คือคอลเล็กชันของแอตทริบิวต์ที่ระบุลักษณะที่ปรากฏของ View
รายการเดียว รูปแบบสามารถระบุแอตทริบิวต์ต่างๆ ได้ เช่น สีแบบอักษร ขนาดแบบอักษร สีพื้นหลัง และอื่นๆ อีกมากมาย
ธีมคือชุดแอตทริบิวต์ที่ใช้กับลําดับชั้นทั้งแอป กิจกรรม หรือมุมมอง ไม่ใช่แค่มุมมองเดียว เมื่อคุณใช้ธีม มุมมองทั้งหมดในแอปหรือกิจกรรมจะใช้แอตทริบิวต์แต่ละรายการของธีมนั้นๆ ที่รองรับ ธีมยังใช้รูปแบบกับองค์ประกอบที่ไม่ใช่มุมมองได้ด้วย เช่น แถบสถานะและพื้นหลังของหน้าต่าง
รูปแบบและธีมจะประกาศในไฟล์ทรัพยากรรูปแบบใน res/values/
ซึ่งมักจะมีชื่อว่า styles.xml
ธีมกับสไตล์
ธีมและสไตล์มีความคล้ายคลึงกันหลายประการ แต่มีไว้เพื่อวัตถุประสงค์ที่แตกต่างกัน ธีมและสไตล์มีโครงสร้างพื้นฐานเหมือนกัน ซึ่งเป็นคู่คีย์-ค่าที่แมปแอตทริบิวต์กับทรัพยากร
style จะระบุแอตทริบิวต์สำหรับมุมมองประเภทหนึ่งๆ เช่น รูปแบบหนึ่งอาจระบุแอตทริบิวต์ของปุ่ม แอตทริบิวต์ทั้งหมดที่คุณระบุในสไตล์คือแอตทริบิวต์ที่คุณตั้งค่าได้ในไฟล์เลย์เอาต์ การสกัดแอตทริบิวต์ทั้งหมดไปยังรูปแบบช่วยให้คุณใช้และดูแลรักษาแอตทริบิวต์เหล่านั้นในวิดเจ็ตหลายรายการได้อย่างง่ายดาย
ธีมจะกำหนดคอลเล็กชันทรัพยากรที่มีชื่อซึ่งอ้างอิงตามสไตล์ เลย์เอาต์ วิดเจ็ต และอื่นๆ ได้ ธีมจะกำหนดชื่อเชิงความหมาย เช่น colorPrimary
ให้กับทรัพยากร Android
สไตล์และธีมมีไว้เพื่อใช้ร่วมกัน เช่น คุณอาจมีสไตล์ที่ระบุว่าส่วนหนึ่งของปุ่มเป็น colorPrimary
และอีกส่วนหนึ่งเป็น colorSecondary
คุณจะดูคำจำกัดความจริงของสีเหล่านั้นได้ในธีม เมื่ออุปกรณ์เข้าสู่โหมดกลางคืน แอปจะเปลี่ยนจากธีม "สว่าง" เป็นธีม "มืด" ได้ ซึ่งจะเปลี่ยนค่าสำหรับชื่อทรัพยากรทั้งหมดเหล่านั้น คุณไม่จําเป็นต้องเปลี่ยนสไตล์ เนื่องจากสไตล์ใช้ชื่อเชิงความหมาย ไม่ใช่คําจํากัดความสีที่เฉพาะเจาะจง
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำงานของธีมและสไตล์ร่วมกันได้ที่บล็อกโพสต์การจัดสไตล์ Android: ธีมกับสไตล์
สร้างและใช้สไตล์
หากต้องการสร้างสไตล์ใหม่ ให้เปิดไฟล์ res/values/styles.xml
ของโปรเจ็กต์ สําหรับสไตล์แต่ละแบบที่ต้องการสร้าง ให้ทําตามขั้นตอนต่อไปนี้
- เพิ่มองค์ประกอบ
<style>
ที่มีชื่อซึ่งระบุสไตล์นั้นๆ ได้อย่างไม่ซ้ำกัน - เพิ่มองค์ประกอบ
<item>
สำหรับแอตทริบิวต์สไตล์แต่ละรายการที่ต้องการกำหนดname
ในแต่ละรายการจะระบุแอตทริบิวต์ที่คุณใช้เป็นแอตทริบิวต์ XML ในเลย์เอาต์ ค่าในองค์ประกอบ<item>
คือค่าสำหรับแอตทริบิวต์นั้น
ตัวอย่างเช่น สมมติว่าคุณกําหนดสไตล์ต่อไปนี้
<?xml version="1.0" encoding="utf-8"?> <resources> <style name="GreenText" parent="TextAppearance.AppCompat"> <item name="android:textColor">#00FF00</item> </style> </resources>
คุณใช้สไตล์กับมุมมองได้โดยทำดังนี้
<TextView style="@style/GreenText" ... />
ระบบจะใช้แอตทริบิวต์แต่ละรายการที่ระบุไว้ในสไตล์กับมุมมองนั้นหากมุมมองยอมรับ มุมมองจะละเว้นแอตทริบิวต์ที่ไม่ยอมรับ
อย่างไรก็ตาม โดยทั่วไปแล้ว คุณจะใช้สไตล์เป็นธีมสำหรับทั้งแอป กิจกรรม หรือคอลเล็กชันของมุมมองแทนการใช้กับแต่ละมุมมอง ตามที่อธิบายไว้ในส่วนอื่นของคู่มือนี้
ขยายและปรับแต่งสไตล์
เมื่อสร้างสไตล์ของคุณเอง ให้ขยายสไตล์ที่มีอยู่จากเฟรมเวิร์กหรือคลังการสนับสนุนเสมอเพื่อให้เข้ากันได้กับสไตล์ UI ของแพลตฟอร์ม หากต้องการขยายสไตล์ ให้ระบุสไตล์ที่ต้องการขยายด้วยแอตทริบิวต์ parent
จากนั้นคุณสามารถลบล้างแอตทริบิวต์สไตล์ที่รับค่ามาและเพิ่มแอตทริบิวต์ใหม่ได้
เช่น คุณสามารถรับค่าลักษณะที่ปรากฏของข้อความเริ่มต้นของแพลตฟอร์ม Android และแก้ไขได้ตามตัวอย่างต่อไปนี้
<style name="GreenText" parent="@android:style/TextAppearance"> <item name="android:textColor">#00FF00</item> </style>
อย่างไรก็ตาม ให้รับรูปแบบแอปหลักจาก Android Support Library เสมอ สไตล์ใน Support Library จะช่วยให้ใช้งานร่วมกันได้โดยการเพิ่มประสิทธิภาพแต่ละสไตล์สำหรับแอตทริบิวต์ UI ที่มีให้ใช้งานในแต่ละเวอร์ชัน สไตล์ของ Support Library มักจะมีชื่อคล้ายกับสไตล์จากแพลตฟอร์ม แต่จะมี AppCompat
อยู่ด้วย
หากต้องการรับค่ารูปแบบจากไลบรารีหรือโปรเจ็กต์ของคุณเอง ให้ประกาศชื่อสไตล์หลักโดยไม่มีส่วน @android:style/
ที่แสดงในตัวอย่างก่อนหน้านี้ ตัวอย่างเช่น ตัวอย่างต่อไปนี้รับรูปแบบลักษณะที่ปรากฏของข้อความมาจากไลบรารีการสนับสนุน
<style name="GreenText" parent="TextAppearance.AppCompat"> <item name="android:textColor">#00FF00</item> </style>
นอกจากนี้ คุณยังรับค่ารูปแบบ (ยกเว้นรูปแบบจากแพลตฟอร์ม) ได้โดยขยายชื่อรูปแบบด้วยเครื่องหมายจุดแทนการใช้แอตทริบิวต์ parent
กล่าวคือ ใส่ชื่อสไตล์ที่ต้องการรับค่าก่อนชื่อสไตล์ของคุณ โดยคั่นด้วยเครื่องหมายจุด โดยปกติแล้ว คุณจะทำเช่นนี้เมื่อขยายสไตล์ของคุณเองเท่านั้น ไม่ใช่สไตล์จากไลบรารีอื่นๆ ตัวอย่างเช่น รูปแบบต่อไปนี้รับค่ารูปแบบทั้งหมดจาก GreenText
ในตัวอย่างก่อนหน้า แล้วเพิ่มขนาดข้อความ
<style name="GreenText.Large"> <item name="android:textSize">22dp</item> </style>
คุณสามารถรับค่ารูปแบบเช่นนี้ซ้ำได้หลายครั้งตามต้องการโดยต่อเชื่อมชื่อเพิ่มเติม
หากต้องการดูว่าแอตทริบิวต์ใดบ้างที่คุณประกาศได้ด้วยแท็ก <item>
โปรดดูตาราง "แอตทริบิวต์ XML" ในข้อมูลอ้างอิงคลาสต่างๆ มุมมองทั้งหมดรองรับแอตทริบิวต์ XML จากคลาส View
พื้นฐาน และมุมมองจํานวนมากจะเพิ่มแอตทริบิวต์พิเศษของตนเอง ตัวอย่างเช่น TextView
แอตทริบิวต์ XML ประกอบด้วยแอตทริบิวต์ android:inputType
ที่คุณสามารถใช้กับวิวข้อความที่รับอินพุต เช่น วิดเจ็ต EditText
ใช้สไตล์เป็นธีม
คุณสร้างธีมได้โดยใช้วิธีเดียวกับการสร้างสไตล์ ความแตกต่างคือวิธีใช้ แทนที่จะใช้รูปแบบที่มีแอตทริบิวต์ style
ในมุมมอง คุณจะใช้ธีมที่มีแอตทริบิวต์ android:theme
ในแท็ก <application>
หรือแท็ก <activity>
ในไฟล์ AndroidManifest.xml
ตัวอย่างเช่น วิธีใช้ธีม "มืด" ของ Material Design ในคลังการสนับสนุนของ Android กับทั้งแอปมีดังนี้
<manifest ... > <application android:theme="@style/Theme.AppCompat" ... > </application> </manifest>
และวิธีใช้ธีม "light" กับกิจกรรมเดียวมีดังนี้
<manifest ... > <application ... > <activity android:theme="@style/Theme.AppCompat.Light" ... > </activity> </application> </manifest>
มุมมองทั้งหมดในแอปหรือกิจกรรมจะใช้สไตล์ที่รองรับจากสไตล์ที่กําหนดไว้ในธีมนั้นๆ หากมุมมองรองรับเฉพาะแอตทริบิวต์บางรายการที่ประกาศไว้ในสไตล์ ระบบจะใช้เฉพาะแอตทริบิวต์เหล่านั้นและละเว้นแอตทริบิวต์ที่ไม่รองรับ
ตั้งแต่ Android 5.0 (API ระดับ 21) และ Android Support Library v22.1 เป็นต้นไป คุณจะระบุแอตทริบิวต์ android:theme
ให้กับมุมมองในไฟล์เลย์เอาต์ได้ด้วย ซึ่งจะแก้ไขธีมสำหรับมุมมองนั้นและมุมมองย่อย ซึ่งมีประโยชน์สำหรับการเปลี่ยนชุดสีของธีมในส่วนที่เฉพาะเจาะจงของอินเทอร์เฟซ
ตัวอย่างก่อนหน้านี้แสดงวิธีใช้ธีม เช่น Theme.AppCompat
ที่มาจาก Android Support Library อย่างไรก็ตาม โดยทั่วไปคุณควรปรับแต่งธีมให้เหมาะกับแบรนด์ของแอป วิธีที่ดีที่สุดคือขยายสไตล์เหล่านี้จากคลังการสนับสนุนและลบล้างแอตทริบิวต์บางส่วนตามที่อธิบายไว้ในส่วนต่อไปนี้
ลําดับชั้นของสไตล์
Android มีวิธีต่างๆ ในการกําหนดแอตทริบิวต์ในแอป Android เช่น คุณกําหนดแอตทริบิวต์ในเลย์เอาต์โดยตรง ใช้สไตล์กับมุมมอง ใช้ธีมกับเลย์เอาต์ และแม้แต่กําหนดแอตทริบิวต์แบบเป็นโปรแกรม
เมื่อเลือกวิธีจัดสไตล์แอป ให้คำนึงถึงลําดับชั้นของสไตล์ Android โดยทั่วไปแล้ว ให้ใช้ธีมและสไตล์ให้มากที่สุดเพื่อให้สอดคล้องกัน หากคุณระบุแอตทริบิวต์เดียวกันในหลายๆ ตําแหน่ง รายการต่อไปนี้จะเป็นตัวกําหนดว่าจะใช้แอตทริบิวต์ใดในท้ายที่สุด รายการจะเรียงลำดับจากความสำคัญสูงสุดไปต่ำสุด
- การใช้การจัดรูปแบบระดับอักขระหรือระดับย่อหน้าโดยใช้ช่วงข้อความกับคลาสที่มาจาก
TextView
- การใช้แอตทริบิวต์แบบเป็นโปรแกรม
- การใช้แอตทริบิวต์แต่ละรายการกับมุมมองโดยตรง
- การใช้รูปแบบกับข้อมูลพร็อพเพอร์ตี้
- การจัดรูปแบบเริ่มต้น
- การใช้ธีมกับคอลเล็กชันมุมมอง กิจกรรม หรือทั้งแอป
- การใช้การจัดรูปแบบที่เจาะจงสำหรับบางมุมมอง เช่น การตั้งค่า
TextAppearance
ในTextView
TextAppearance
ข้อจํากัดอย่างหนึ่งของสไตล์คือคุณใช้สไตล์กับ View
ได้เพียงสไตล์เดียว อย่างไรก็ตาม ใน TextView
คุณยังระบุแอตทริบิวต์ TextAppearance
ที่ทํางานคล้ายกับสไตล์ได้ด้วย ดังที่แสดงในตัวอย่างต่อไปนี้
<TextView ... android:textAppearance="@android:style/TextAppearance.Material.Headline" android:text="This text is styled via textAppearance!" />
TextAppearance
ช่วยให้คุณกำหนดการจัดรูปแบบเฉพาะข้อความได้ในขณะที่ยังคงใช้สไตล์ของ View
กับการใช้งานอื่นๆ ได้ อย่างไรก็ตาม โปรดทราบว่าหากคุณกำหนดแอตทริบิวต์ข้อความใน View
หรือในสไตล์โดยตรง ค่าเหล่านั้นจะลบล้างค่า TextAppearance
TextAppearance
รองรับชุดย่อยของแอตทริบิวต์การจัดรูปแบบที่ TextView
มีให้ ดูรายการแอตทริบิวต์ทั้งหมดได้ในส่วน
TextAppearance
แอตทริบิวต์ TextView
ทั่วไปบางรายการที่ไม่ได้รวมอยู่มีดังนี้
lineHeight[Multiplier|Extra]
,
lines
,
breakStrategy
และ
hyphenationFrequency
TextAppearance
ทำงานที่ระดับอักขระ ไม่ใช่ระดับย่อหน้า ระบบจึงไม่รองรับแอตทริบิวต์ที่ส่งผลต่อเลย์เอาต์ทั้งหน้า
ปรับแต่งธีมเริ่มต้น
เมื่อคุณสร้างโปรเจ็กต์ด้วย Android Studio ระบบจะใช้ธีม Material Design กับแอปโดยค่าเริ่มต้นตามที่ระบุไว้ในไฟล์ styles.xml
ของโปรเจ็กต์ สไตล์ AppTheme
นี้เป็นการขยายธีมจากไลบรารีการสนับสนุน รวมถึงการลบล้างแอตทริบิวต์สีที่ใช้โดยองค์ประกอบ UI หลัก เช่น แถบแอปและปุ่มการดำเนินการแบบลอย (หากมี) คุณจึงปรับแต่งการออกแบบสีของแอปได้อย่างรวดเร็วด้วยการอัปเดตสีที่ระบุ
เช่น ไฟล์ styles.xml
มีลักษณะดังนี้
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="colorPrimary">@color/colorPrimary</item> <item name="colorPrimaryDark">@color/colorPrimaryDark</item> <item name="colorAccent">@color/colorAccent</item> </style>
ค่าสไตล์ที่แท้จริงคือการอ้างอิงถึงทรัพยากรสีอื่นๆ ซึ่งกำหนดไว้ในไฟล์ res/values/colors.xml
ของโปรเจ็กต์ ไฟล์ดังกล่าวคือไฟล์ที่คุณแก้ไขเพื่อเปลี่ยนสี
ดูภาพรวมสีของ Material Design เพื่อปรับปรุงประสบการณ์ของผู้ใช้ด้วยสีแบบไดนามิกและสีที่กำหนดเองเพิ่มเติม
เมื่อทราบสีแล้ว ให้อัปเดตค่าใน res/values/colors.xml
โดยทำดังนี้
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- Color for the app bar and other primary UI elements. --> <color name="colorPrimary">#3F51B5</color> <!-- A darker variant of the primary color, used for the status bar (on Android 5.0+) and contextual app bars. --> <color name="colorPrimaryDark">#303F9F</color> <!-- a secondary color for controls like checkboxes and text fields. --> <color name="colorAccent">#FF4081</color> </resources>
จากนั้นคุณสามารถลบล้างสไตล์อื่นๆ ที่ต้องการ เช่น คุณเปลี่ยนสีพื้นหลังของกิจกรรมได้ดังนี้
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> ... <item name="android:windowBackground">@color/activityBackground</item> </style>
ดูรายการแอตทริบิวต์ที่คุณใช้ในธีมได้ที่ตารางแอตทริบิวต์ที่ R.styleable.Theme
เมื่อเพิ่มสไตล์สำหรับมุมมองในเลย์เอาต์ คุณยังดูแอตทริบิวต์ได้โดยดูที่ตาราง "แอตทริบิวต์ XML" ในข้อมูลอ้างอิงคลาสมุมมอง ตัวอย่างเช่น มุมมองทั้งหมดรองรับแอตทริบิวต์ XML จากView
คลาสพื้นฐาน
แอตทริบิวต์ส่วนใหญ่จะมีผลกับมุมมองบางประเภท และบางแอตทริบิวต์จะมีผลกับทุกมุมมอง อย่างไรก็ตาม แอตทริบิวต์ธีมบางรายการที่แสดงใน R.styleable.Theme
จะมีผลกับหน้าต่างกิจกรรม ไม่ใช่มุมมองในเลย์เอาต์ เช่น windowBackground
เปลี่ยนพื้นหลังของหน้าต่าง และ windowEnterTransition
กําหนดภาพเคลื่อนไหวการเปลี่ยนฉากที่จะใช้เมื่อกิจกรรมเริ่มต้น โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อเริ่มกิจกรรมโดยใช้ภาพเคลื่อนไหว
ไลบรารีการสนับสนุนของ Android ยังมีแอตทริบิวต์อื่นๆ ที่คุณสามารถใช้เพื่อปรับแต่งธีมซึ่งขยายมาจาก Theme.AppCompat
เช่น แอตทริบิวต์ colorPrimary
ที่แสดงในตัวอย่างก่อนหน้านี้ ไฟล์เหล่านี้เหมาะสําหรับดูในไฟล์ attrs.xml
ของคลัง
นอกจากนี้ยังมีธีมอื่นๆ จากคลังการสนับสนุนที่คุณอาจต้องการขยายใช้แทนธีมที่แสดงในตัวอย่างก่อนหน้านี้ แหล่งที่ดีที่สุดในการดูธีมที่ใช้ได้มีไฟล์ themes.xml
ของไลบรารี
เพิ่มรูปแบบเฉพาะเวอร์ชัน
หาก Android เวอร์ชันใหม่เพิ่มแอตทริบิวต์ธีมที่ต้องการใช้ คุณสามารถเพิ่มแอตทริบิวต์ดังกล่าวลงในธีมได้ในขณะที่ยังคงใช้งานร่วมกับเวอร์ชันเก่าได้ สิ่งที่ต้องมีคือไฟล์ styles.xml
ไฟล์อื่นที่บันทึกไว้ในไดเรกทอรี values
ซึ่งมีตัวระบุเวอร์ชันทรัพยากร ดังนี้
res/values/styles.xml # themes for all versions res/values-v21/styles.xml # themes for API level 21+ only
เนื่องจากรูปแบบในไฟล์ values/styles.xml
ใช้ได้กับทุกเวอร์ชัน ธีมของคุณใน values-v21/styles.xml
จึงรับรูปแบบเหล่านั้นได้ ซึ่งหมายความว่าคุณจะหลีกเลี่ยงการใช้สไตล์ซ้ำได้โดยเริ่มจากธีม "พื้นฐาน" แล้วขยายธีมนั้นในสไตล์สำหรับเวอร์ชันที่เฉพาะเจาะจง
เช่น หากต้องการประกาศการเปลี่ยนเฟรมของหน้าต่างสำหรับ Android 5.0 (API ระดับ 21) ขึ้นไป คุณต้องใช้แอตทริบิวต์ใหม่ ดังนั้นธีมพื้นฐานใน res/values/styles.xml
จึงอาจมีลักษณะดังนี้
<resources> <!-- Base set of styles that apply to all versions. --> <style name="BaseAppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="colorPrimary">@color/primaryColor</item> <item name="colorPrimaryDark">@color/primaryTextColor</item> <item name="colorAccent">@color/secondaryColor</item> </style> <!-- Declare the theme name that's actually applied in the manifest file. --> <style name="AppTheme" parent="BaseAppTheme" /> </resources>
จากนั้นเพิ่มสไตล์สำหรับเวอร์ชันที่เฉพาะเจาะจงใน res/values-v21/styles.xml
ดังนี้
<resources> <!-- extend the base theme to add styles available only with API level 21+ --> <style name="AppTheme" parent="BaseAppTheme"> <item name="android:windowActivityTransitions">true</item> <item name="android:windowEnterTransition">@android:transition/slide_right</item> <item name="android:windowExitTransition">@android:transition/slide_left</item> </style> </resources>
ตอนนี้คุณใช้ AppTheme
ในไฟล์ Manifest ได้ และระบบจะเลือกสไตล์ที่ใช้ได้สำหรับระบบแต่ละเวอร์ชัน
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ทรัพยากรทางเลือกสำหรับอุปกรณ์ต่างๆ ได้ที่การจัดหาทรัพยากรทางเลือก
ปรับแต่งสไตล์วิดเจ็ต
วิดเจ็ตทุกรายการในเฟรมเวิร์กและคลังการสนับสนุนมีรูปแบบเริ่มต้น เช่น เมื่อคุณจัดสไตล์แอปโดยใช้ธีมจากคลังการสนับสนุน ระบบจะจัดสไตล์อินสแตนซ์ของ Button
โดยใช้สไตล์ Widget.AppCompat.Button
หากต้องการใช้สไตล์วิดเจ็ตอื่นกับปุ่ม ให้ใช้แอตทริบิวต์ style
ในไฟล์เลย์เอาต์ ตัวอย่างเช่น ข้อความต่อไปนี้ใช้สไตล์ปุ่มแบบไม่มีขอบของไลบรารี
<Button style="@style/Widget.AppCompat.Button.Borderless" ... />
หากต้องการใช้สไตล์นี้กับปุ่มทั้งหมด ให้ประกาศสไตล์นั้นในธีม
buttonStyle
ดังนี้
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item name="buttonStyle">@style/Widget.AppCompat.Button.Borderless</item> ... </style>
นอกจากนี้ คุณยังขยายสไตล์วิดเจ็ตได้เช่นเดียวกับการขยายสไตล์อื่นๆ แล้วนำไปใช้กับสไตล์วิดเจ็ตที่กำหนดเองในเลย์เอาต์หรือธีม
แหล่งข้อมูลเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับธีมและสไตล์ได้ที่แหล่งข้อมูลต่อไปนี้
บล็อกโพสต์
- การจัดสไตล์ Android: ธีมกับสไตล์
- การจัดสไตล์ Android: แอตทริบิวต์ธีมทั่วไป
- การจัดสไตล์ Android: แนะนำให้ใช้แอตทริบิวต์ธีม