Toast และ Custom Toast
Toast คือข้อความแจ้งเตือนเล็กน้อย แสดงชั่วคราวแล้วหายเอง Custom Toast คือการปรับแต่ง Layout, สี, ฟอนต์, ไอคอน, Animation ให้ตรงกับ Brand/Design System ของแอป
วิธีสร้าง Custom Toast แบบ XML Layout
1. สร้าง Layout: res/layout/custom_toast.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:id="@+id/custom_toast_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/toast_background"
android:orientation="horizontal"
android:padding="12dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/toast_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="12dp"
android:src="@drawable/ic_check_circle"
android:contentDescription="@string/toast_success_icon" />
<TextView
android:id="@+id/toast_message"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Custom Toast Message"
android:textColor="@android:color/white"
android:textSize="14sp"
android:maxLines="2"
android:ellipsize="end" />
</LinearLayout>
2. สร้าง Background Drawable: res/drawable/toast_background.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="https://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#323232" /> <!-- Dark Gray -->
<corners android:radius="12dp" />
<padding
android:left="16dp"
android:top="12dp"
android:right="16dp"
android:bottom="12dp" />
<!-- Optional: Shadow (API 28+) -->
<!-- 需要在 Layer List 中配合 elevation 使用 -->
</shape>
3. Helper Class: CustomToast.java
import android.content.Context;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class CustomToast {
public static final int TYPE_SUCCESS = 0;
public static final int TYPE_ERROR = 1;
public static final int TYPE_WARNING = 2;
public static final int TYPE_INFO = 3;
public static void show(Context context, String message, int type) {
show(context, message, type, Toast.LENGTH_SHORT);
}
public static void show(Context context, String message, int type, int duration) {
// Inflate layout
LayoutInflater inflater = LayoutInflater.from(context);
View layout = inflater.inflate(R.layout.custom_toast, null);
// Setup views
ImageView icon = layout.findViewById(R.id.toast_icon);
TextView text = layout.findViewById(R.id.toast_message);
text.setText(message);
// Set icon & color by type
switch (type) {
case TYPE_SUCCESS:
icon.setImageResource(R.drawable.ic_check_circle);
layout.setBackgroundResource(R.drawable.toast_bg_success); // Green tint
break;
case TYPE_ERROR:
icon.setImageResource(R.drawable.ic_error);
layout.setBackgroundResource(R.drawable.toast_bg_error); // Red tint
break;
case TYPE_WARNING:
icon.setImageResource(R.drawable.ic_warning);
layout.setBackgroundResource(R.drawable.toast_bg_warning); // Orange tint
break;
case TYPE_INFO:
default:
icon.setImageResource(R.drawable.ic_info);
layout.setBackgroundResource(R.drawable.toast_bg_info); // Blue tint
break;
}
// Create and show Toast
Toast toast = new Toast(context);
toast.setDuration(duration);
toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 100); // Offset from bottom
toast.setView(layout);
toast.show();
}
// Convenience methods
public static void success(Context context, String msg) { show(context, msg, TYPE_SUCCESS); }
public static void error(Context context, String msg) { show(context, msg, TYPE_ERROR); }
public static void warning(Context context, String msg) { show(context, msg, TYPE_WARNING); }
public static void info(Context context, String msg) { show(context, msg, TYPE_INFO); }
}
4. ใช้งานใน Activity/Fragment
// เรียกใช้ง่ายๆ CustomToast.success(this, "บันทึกข้อมูลสำเร็จ!"); CustomToast.error(this, "เกิดข้อผิดพลาด: ไม่สามารถเชื่อมต่อเซิร์ฟเวอร์"); CustomToast.warning(this, "กรุณากรอกข้อมูลให้ครบถ้วน"); CustomToast.info(this, "มีการอัปเดตใหม่"); // หรือใช้แบบกำหนด Duration เอง CustomToast.show(this, "ข้อความยาวขึ้น...", CustomToast.TYPE_INFO, Toast.LENGTH_LONG);
วิธีทันสมัย: ใช้ Snackbar (แนะนำ)
Material Design แนะนำให้ใช้ Snackbar** แทน Toast เพราะ:
- มี Action Button ได้ (Undo, Retry, Dismiss)
- อยู่เหนือ UI อื่นๆ (ไม่บังเนื้อหา)
- Animation สวยงาม ทันสมัย
- รองรับ Swipe to Dismiss
ตัวอย่าง Snackbar
import com.google.android.material.snackbar.Snackbar;
import androidx.core.content.ContextCompat;
// ใน Activity/Fragment (ต้องมี CoordinatorLayout หรือ ViewGroup เป็น Root)
View rootView = findViewById(android.R.id.content); // หรือ CoordinatorLayout
Snackbar snackbar = Snackbar.make(rootView, "ข้อความแจ้งเตือน", Snackbar.LENGTH_LONG)
.setAction("UNDO", v -> { /* ทำ Undo */ })
.setActionTextColor(ContextCompat.getColor(this, R.color.accent))
.setBackgroundTint(ContextCompat.getColor(this, R.color.surface))
.setTextColor(ContextCompat.getColor(this, R.color.onSurface));
// Custom View (Advanced)
Snackbar.make(rootView, "", Snackbar.LENGTH_INDEFINITE)
.setContentView(R.layout.custom_snackbar_layout) // API 30+ / Material 1.5+
.show();
snackbar.show();
Toast แบบไม่ใช้ Layout XML (Programmatic)
public static void showSimpleToast(Context context, String message, int backgroundColor, int textColor) {
Toast toast = new Toast(context);
TextView textView = new TextView(context);
textView.setText(message);
textView.setTextColor(textColor);
textView.setTextSize(14);
textView.setPadding(24, 16, 24, 16);
textView.setBackgroundColor(backgroundColor);
// Rounded corners ต้องใช้ Background Drawable แทน
toast.setView(textView);
toast.setDuration(Toast.LENGTH_SHORT);
toast.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, 100);
toast.show();
}
ข้อจำกัดและข้อควรระวัง
- Position: Toast ตำแหน่งคงที่ (Top/Center/Bottom) ไม่สามารถวางได้ตามต้องการแบบ Pixel Perfect
- Queue: Toast หลายตัวจะคิวไว้แสดงทีละอัน (ไม่ทับกัน)
- System Overlay: Android 12+ จำกัด Toast จาก Background Service/Receiver
- Custom View Limitation: ไม่รองรับ Interactive View (Button, EditText) ภายใน Toast
- Memory: Inflate Layout ทุกครั้งอาจช้า → Cache View หรือใช้ Singleton Pattern
Library แนะนำ (Modern Alternatives)
- Toasty - Gionee/Toasty: `Toasty.success(context, "Success").show();`
- Crouton - Rich Toast (Deprecated)
- SuperToasts - Feature-rich
- Snackbar (Material) - Built-in, Best Practice
สรุป
- ใช้ Custom Toast Layout + Helper Class สำหรับโปรเจกต์ที่ยังใช้ Toast
- ย้ายไปใช้ Snackbar สำหรับโปรเจกต์ใหม่ (Material Design Standard)
- หลีกเลี่ยง Toast ใน Background/Service (Android 12+ Block)
- พิจารณา Library Toasty หากต้องการความสะดวกและสวยงามโดยไม่อยากเขียนเอง