Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Android

วิธีเปลี่ยนไอคอน Overflow Menu ใน Toolbar แบบโปรแกรมมัติด้วย Kotlin

ตัวอย่างนี้สาธิตวิธี ปรับแต่ง Overflow Menu (สามจุด) ใน Toolbar รวมถึงการเปลี่ยน Icon, ซ่อน/แสดง Menu Item แบบไดนามิก

ขั้นตอนที่ 1: สร้างโปรเจกต์ใหม่

Android Studio → New Project → Empty Activity (Theme: MaterialComponents)

ขั้นตอนที่ 2: Layout (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.appcompat.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.MaterialComponents.Dark.ActionBar"
        app:popupTheme="@style/ThemeOverlay.MaterialComponents.Light" />

</LinearLayout>

ขั้นตอนที่ 3: Menu Resource (res/menu/main_menu.xml)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto">

    <item
        android:id="@+id/menu_bluetooth"
        android:icon="@drawable/ic_bluetooth"
        android:title="Bluetooth"
        app:showAsAction="ifRoom" />

    <item
        android:id="@+id/menu_call"
        android:icon="@drawable/ic_call"
        android:title="Call"
        app:showAsAction="ifRoom|collapseActionView" />

    <item
        android:id="@+id/menu_chat"
        android:icon="@drawable/ic_chat"
        android:title="Chat"
        android:visible="false"
        app:showAsAction="ifRoom|collapseActionView" />

    <item
        android:id="@+id/menu_about"
        android:title="About"
        app:showAsAction="never" />

</menu>

ขั้นตอนที่ 4: โค้ดหลัก (MainActivity.kt)

import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.widget.Toolbar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    private lateinit var toolbar: Toolbar

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        title = "Toolbar Menu Demo"

        toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

        // 🔑 เปลี่ยน Overflow Icon (สามจุด) แบบโปรแกรมมัติ
        // ต้องทำหลัง setSupportActionBar
        val overflowIcon = ContextCompat.getDrawable(this, R.drawable.ic_custom_overflow)
        overflowIcon?.let { toolbar.setOverflowIcon(it) }
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        menuInflater.inflate(R.menu.main_menu, menu)
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when (item.itemId) {
            R.id.menu_bluetooth -> {
                Toast.makeText(this, "Bluetooth clicked", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.menu_call -> {
                Toast.makeText(this, "Call clicked", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.menu_chat -> {
                Toast.makeText(this, "Chat clicked", Toast.LENGTH_SHORT).show()
                true
            }
            R.id.menu_about -> {
                Toast.makeText(this, "About clicked", Toast.LENGTH_SHORT).show()
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

    // 🔑 จุดสำคัญ: ปรับ Menu แบบไดนามิก (ซ่อน/แสดง/เปลี่ยน Icon)
    override fun onPrepareOptionsMenu(menu: Menu): Boolean {
        // เรียกทุกครั้งก่อน Menu แสดง
        val callItem = menu.findItem(R.id.menu_call)
        val chatItem = menu.findItem(R.id.menu_chat)

        // ตัวอย่าง: สลับการแสดง Call/Chat
        callItem.isVisible = false
        chatItem.isVisible = true

        // เปลี่ยน Icon ของ Bluetooth
        val btItem = menu.findItem(R.id.menu_bluetooth)
        btItem.icon = ContextCompat.getDrawable(this, R.drawable.ic_bluetooth_connected)

        return super.onPrepareOptionsMenu(menu)
    }
}

🎨 เปลี่ยน Overflow Icon ผ่าน Theme (XML) - วิธีมาตรฐาน

<!-- res/values/styles.xml -->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.DarkActionBar">
    <item name="actionOverflowButtonStyle">@style/CustomOverflow</item>
</style>

<style name="CustomOverflow" parent="Widget.AppCompat.ActionButton.Overflow">
    <item name="android:src">@drawable/ic_custom_overflow</item>
</style>

🔧 Vector Drawable สำหรับ Overflow Icon (res/drawable/ic_custom_overflow.xml)

<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="https://schemas.android.com/apk/res/android"
    android:width="24dp"
    android:height="24dp"
    android:viewportWidth="24"
    android:viewportHeight="24">
    <path
        android:fillColor="@android:color/white"
        android:pathData="M12,16c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4s4,1.79 4,4s-1.79,4 -4,4zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2s-0.9,-2 -2,-2zM12,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2s2,-0.9 2,-2s-0.9,-2 -2,-2z" />
</vector>

💡 เคล็ดลับเพิ่มเติม

  • app:showAsAction="ifRoom": แสดงใน Toolbar ถ้ามีที่, ไม่งั้นไป Overflow
  • app:showAsAction="never": บังคับให้อยู่ใน Overflow เท่านั้น
  • app:showAsAction="always": บังคับแสดงใน Toolbar (อาจทับกัน)
  • collapseActionView: ใช้กับ SearchView, Custom View
  • ใช้ menu.findItem(id).setVisible(false) ซ่อน Item
  • ใช้ menu.findItem(id).icon = newDrawable เปลี่ยน Icon

ขั้นตอนที่ 5: AndroidManifest.xml

Manifest มาตรฐาน (Theme ตั้งใน Application/Activity)

ทดสอบ

  1. รันแอป → Toolbar แสดง Icon Bluetooth, Overflow Icon เป็น Custom
  2. กด Overflow (สามจุด) → เมนูแสดง About (Chat ซ่อน, Call ซ่อน)
  3. กด About → Toast แสดง