Snackbar là component Material Design hiển thị thông báo nhẹ ở dưới màn hình, có thể chứa action (Undo, Retry, Dismiss...). Khác với Toast: Snackbar gắn với View hierarchy, có action, swipe để dismiss, animation mượt mà.
Dependency
dependencies {
// Material Components (đã có Snackbar)
implementation 'com.google.android.material:material:1.11.0'
// Hoặc legacy support library
// implementation 'com.android.support:design:28.0.0'
}
Yêu cầu: CoordinatorLayout
Snackbar cần CoordinatorLayout làm parent để hiển thị đúng vị trí, tránh che FAB, xử lý swipe dismiss, layout_anchor.
Layout activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="FAB"
android:src="@drawable/ic_add"
app:layout_anchor="@id/bottomView"
app:layout_anchorGravity="bottom|right|end" />
<LinearLayout
android:id="@+id/bottomView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical"
android:padding="16dp">
<Button
android:id="@+id/btnSimpleSnackbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Snackbar đơn giản" />
<Button
android:id="@+id/btnActionSnackbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Snackbar có Action (Undo)" />
<Button
android:id="@+id/btnCustomSnackbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Snackbar tùy chỉnh màu/chữ" />
</LinearLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MainActivity.java - Các loại Snackbar
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.snackbar.Snackbar;
public class MainActivity extends AppCompatActivity {
private CoordinatorLayout coordinatorLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
coordinatorLayout = findViewById(R.id.coordinatorLayout);
findViewById(R.id.btnSimpleSnackbar).setOnClickListener(v -> showSimpleSnackbar());
findViewById(R.id.btnActionSnackbar).setOnClickListener(v -> showActionSnackbar());
findViewById(R.id.btnCustomSnackbar).setOnClickListener(v -> showCustomSnackbar());
}
// 1. Snackbar đơn giản
private void showSimpleSnackbar() {
Snackbar.make(coordinatorLayout, "Đã lưu thay đổi", Snackbar.LENGTH_LONG)
.show();
}
// 2. Snackbar với Action (Undo, Retry...)
private void showActionSnackbar() {
Snackbar.make(coordinatorLayout, "Mục đã bị xóa", Snackbar.LENGTH_LONG)
.setAction("Hoàn tác", v -> {
Toast.makeText(this, "Đã hoàn tác xóa", Toast.LENGTH_SHORT).show();
// Thực hiện undo logic ở đây
})
.setActionTextColor(Color.YELLOW) // Màu chữ action
.addCallback(new Snackbar.Callback() {
@Override
public void onDismissed(Snackbar transientBottomBar, int event) {
super.onDismissed(transientBottomBar, event);
// event: DISMISS_EVENT_SWIPE, DISMISS_EVENT_ACTION, DISMISS_EVENT_TIMEOUT, DISMISS_EVENT_MANUAL, DISMISS_EVENT_CONSECUTIVE
}
@Override
public void onShown(Snackbar sb) {
super.onShown(sb);
}
})
.show();
}
// 3. Snackbar tùy chỉnh màu, text, duration
private void showCustomSnackbar() {
Snackbar snackbar = Snackbar.make(coordinatorLayout, "Kết nối mạng thất bại", Snackbar.LENGTH_INDEFINITE)
.setAction("Thử lại", v -> {
// Retry logic
Toast.makeText(this, "Đang thử lại...", Toast.LENGTH_SHORT).show();
})
.setActionTextColor(getColor(R.color.design_default_color_error)) // Màu đỏ
.setTextColor(Color.WHITE) // Màu text chính
.setBackgroundTint(Color.parseColor("#FF5722")) // Màu background (Material 1.2+)
// .setBackgroundTintList(ColorStateList.valueOf(Color.parseColor("#FF5722"))) // Old API
.setDuration(5000) // Custom duration (ms)
.setAnimationMode(BaseTransientBottomBar.ANIMATION_MODE_SLIDE); // Slide/Fade
// Custom view (nâng cao)
View snackbarView = snackbar.getView();
TextView textView = snackbarView.findViewById(com.google.android.material.R.id.snackbar_text);
textView.setMaxLines(3); // Cho phép multi-line
textView.setTextSize(15);
snackbar.show();
}
}
Snackbar vs Toast
| Đặc điểm | Snackbar | Toast |
|---|---|---|
| Vị trí | Dưới cùng, trên FAB/Navigation | Dưới cùng, fixed |
| Action button | Có (setAction) | Không |
| Swipe dismiss | Có | Không |
| Animation | Slide up/down mượt | Fade in/out đơn giản |
| Custom layout | Khó (chỉ màu/text) | Dễ (setView) |
| Context cần | View (CoordinatorLayout) | Context bất kỳ |
| Blocking | Không block touch khác | Không block |
Các Duration có sẵn
Snackbar.LENGTH_SHORT~ 1500msSnackbar.LENGTH_LONG~ 2700msSnackbar.LENGTH_INDEFINITEVô thời hạn (cần action hoặc swipe dismiss)setDuration(int ms)Tùy chỉnh (API 1.2+)
Snackbar trong Fragment
// Cần view root của Fragment (thường là view trả về trong onCreateView) View rootView = getView(); // hoặc binding.getRoot() Snackbar.make(rootView, "Message", Snackbar.LENGTH_SHORT).show(); // Hoặc dùng requireActivity() tìm CoordinatorLayout CoordinatorLayout coordinator = requireActivity().findViewById(R.id.coordinatorLayout); Snackbar.make(coordinator, "Message", Snackbar.LENGTH_SHORT).show();
Snackbar với Custom Layout (Nâng cao)
Snackbar không hỗ trợ setView như Toast. Để custom hoàn toàn, dùng BottomSheetDialogFragment hoặc library FancyToast, SnackbarUtils.
Chạy ứng dụng
Nhấn các nút → Snackbar xuất hiện từ dưới lên, không che FAB (nhờ CoordinatorLayout). Snackbar có action hiển thị nút "Hoàn tác"/"Thử lại" màu vàng/đỏ. Swipe sang trái/phải để dismiss sớm.
Lưu ý
- Phải có CoordinatorLayout trong hierarchy (thường là root layout)
- Snackbar.make(view, ...) - view dùng để tìm CoordinatorLayout ancestor
- Tránh show nhiều Snackbar cùng lúc - sẽ queue tự động
- setBackgroundTint cần Material 1.2+, cũ dùng setBackgroundTintList
- Text color/action color nên contrast với background