Hướng dẫn này trình bày cách triển khai Bottom Sheet (bảng trượt từ dưới lên) sử dụng Design Support Library và ButterKnife (thư viện view binding cũ). Bottom Sheet là thành phần UI Material Design phổ biến cho menu ngữ cảnh, chi tiết đơn hàng, bộ lọc, v.v.
Lưu ý: ButterKnife đã deprecated (ngừng phát triển). Dự án mới nên dùng View Binding (built-in) hoặc Data Binding. Code dưới đây đã được cập nhật dùng View Binding.
Các bước thực hiện
Bước 1: Tạo dự án mới
Mở Android Studio, chọn File → New Project và điền thông tin cần thiết.
Bước 2: Thêm dependency (build.gradle Module:app)
dependencies {
// Material Components (bao gồm BottomSheetBehavior)
implementation 'com.google.android.material:material:1.9.0'
// View Binding (thay thế ButterKnife) - bật trong android block:
// buildFeatures { viewBinding true }
}
Bước 3: Layout chính (res/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"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content" />
<!-- Bottom Sheet đặt SAU content chính -->
<include layout="@layout/bottom_sheet" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Bước 4: Layout nội dung chính (res/layout/content.xml)
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:tools="https://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<Button
android:id="@+id/btnBottomSheet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hiện Bottom Sheet"
android:layout_centerInParent="true"/>
</RelativeLayout>
Bước 5: Layout Bottom Sheet (res/layout/bottom_sheet.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:id="@+id/bottomSheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp"
app:behavior_hideable="true"
app:behavior_peekHeight="60dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_vertical"
android:weightSum="3">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
android:text="Chi tiết đơn hàng"
android:textColor="#444"
android:textSize="18sp"
android:textStyle="bold" />
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="₫435.000"
android:textSize="15sp"
android:textStyle="bold" />
</LinearLayout>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Gà nướng BBQ" android:layout_marginTop="8dp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Cơm gà xối mỡ" android:layout_marginTop="4dp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Địa chỉ giao hàng" android:textColor="#444" android:textStyle="bold" android:layout_marginTop="16dp"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Số 123, Đường ABC, Quận 1, TP.HCM" android:layout_marginTop="4dp"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:backgroundTint="#000000"
android:text="THANH TOÁN"
android:textColor="#FFFFFF" />
</LinearLayout>
Bước 6: MainActivity với View Binding (src/MainActivity.java)
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
// Import class binding tự động sinh ra (tên = tên file layout + Binding)
import com.example.myapp.databinding.ActivityMainBinding;
import com.example.myapp.databinding.BottomSheetBinding;
import com.example.myapp.databinding.ContentBinding;
public class MainActivity extends AppCompatActivity {
// View Binding instances
private ActivityMainBinding mainBinding;
private BottomSheetBinding sheetBinding;
private ContentBinding contentBinding;
private BottomSheetBehavior<LinearLayout> sheetBehavior;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Inflate main layout qua View Binding
mainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(mainBinding.getRoot());
// Inflate content layout (được include trong main)
contentBinding = ContentBinding.bind(mainBinding.content.getRoot());
// Inflate bottom sheet layout
sheetBinding = BottomSheetBinding.bind(mainBinding.bottomSheet.getRoot());
// Toolbar
Toolbar toolbar = mainBinding.toolbar;
setSupportActionBar(toolbar);
// Lấy BottomSheetBehavior từ root view của bottom sheet
LinearLayout bottomSheetView = sheetBinding.bottomSheet;
sheetBehavior = BottomSheetBehavior.from(bottomSheetView);
// Callback theo dõi trạng thái
sheetBehavior.addBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
@Override
public void onStateChanged(@NonNull View bottomSheet, int newState) {
switch (newState) {
case BottomSheetBehavior.STATE_EXPANDED:
contentBinding.btnBottomSheet.setText("Đóng Sheet");
break;
case BottomSheetBehavior.STATE_COLLAPSED:
contentBinding.btnBottomSheet.setText("Mở rộng Sheet");
break;
case BottomSheetBehavior.STATE_HIDDEN:
// Sheet bị ẩn hoàn toàn (khi behavior_hideable=true và user swipe down)
break;
case BottomSheetBehavior.STATE_DRAGGING:
case BottomSheetBehavior.STATE_SETTLING:
// Đang kéo / đang落ち着く
break;
}
}
@Override
public void onSlide(@NonNull View bottomSheet, float slideOffset) {
// slideOffset: 0.0 (collapsed) -> 1.0 (expanded)
// Có thể dùng để animate các view bên trong
}
});
// Xử lý click nút trên content
contentBinding.btnBottomSheet.setOnClickListener(v -> toggleBottomSheet());
}
private void toggleBottomSheet() {
if (sheetBehavior.getState() != BottomSheetBehavior.STATE_EXPANDED) {
sheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
contentBinding.btnBottomSheet.setText("Đóng Sheet");
} else {
sheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
contentBinding.btnBottomSheet.setText("Mở rộng Sheet");
}
}
}
Bước 7: Cấu hình AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
package="com.example.myapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MaterialComponents.DayNight.NoActionBar">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Chạy ứng dụng
Kết nối thiết bị, nhấn Run. Nhấn nút "Hiện Bottom Sheet" - bảng sẽ trượt lên từ dưới. Kéo thả để mở rộng/thu gọn.

Các trạng thái BottomSheetBehavior
| Trạng thái | Mô tả |
|---|---|
STATE_COLLAPSED |
Thu gọn, chỉ hiển thị peekHeight (mặc định 0) |
STATE_EXPANDED |
Mở rộng đầy đủ nội dung |
STATE_DRAGGING |
Người dùng đang kéo |
STATE_SETTLING |
Đang animation về trạng thái ổn định |
STATE_HIDDEN |
Ẩn hoàn toàn (cần behavior_hideable="true") |
STATE_HALF_EXPANDED |
Nửa mở (API 30+, Material 1.5+) |
Thuộc tính XML quan trọng
app:layout_behavior: Bắt buộc =com.google.android.material.bottomsheet.BottomSheetBehaviorapp:behavior_peekHeight: Chiều cao khi collapsed (dp)app:behavior_hideable:truecho phép swipe down để ẩn hẳnapp:behavior_skipCollapsed:truebỏ qua trạng thái collapsed khi expandapp:behavior_fitToContents:true(mặc định) - height theo nội dung;false- full màn hình
BottomSheetDialogFragment (Dialog modal từ dưới lên)
Cho trường hợp cần dialog modal (chặn tương tác nền):
public class MyBottomSheetDialog extends BottomSheetDialogFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.bottom_sheet_dialog, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Xử lý view
}
}
// Hiển thị:
new MyBottomSheetDialog().show(getSupportFragmentManager(), "TAG");