Hướng dẫn này trình bày cách tạo Tab Layout kết hợp với ViewPager trong Android sử dụng Material Design Components. Tab Layout cho phép chuyển đổi giữa các trang (Fragment) bằng cách nhấn vào tab hoặc vuốt ngang.
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 TabLayout, ViewPager2)
implementation 'com.google.android.material:material:1.9.0'
// Fragment & ViewPager2 (AndroidX)
implementation 'androidx.fragment:fragment:1.6.1'
implementation 'androidx.viewpager2:viewpager2:1.0.0'
}
Lưu ý: Code gốc dùng android.support.design:design:28.0.0 (thư viện Support cũ, đã ngừng hỗ trợ). Phiên bản trên dùng AndroidX + Material Components hiện đại.
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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:tabTextColor="?attr/colorOnSurface"
app:tabSelectedTextColor="?attr/colorOnPrimary"
app:tabIndicatorColor="?attr/colorOnPrimary"
app:tabGravity="fill"
app:tabMode="fixed" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Bước 4: MainActivity (src/MainActivity.java)
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
public class MainActivity extends AppCompatActivity {
TabLayout tabLayout;
ViewPager2 viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tabLayout = findViewById(R.id.tabLayout);
viewPager = findViewById(R.id.viewPager);
// Adapter cho ViewPager2
MyAdapter adapter = new MyAdapter(this);
viewPager.setAdapter(adapter);
// TabLayoutMediator: Kết nối TabLayout với ViewPager2 (thay thế TabLayout.OnTabSelectedListener + ViewPager.addOnPageChangeListener)
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
switch (position) {
case 0: tab.setText("Bóng đá"); break;
case 1: tab.setText("Cricket"); break;
case 2: tab.setText("NBA"); break;
}
}).attach();
}
}
Bước 5: Adapter cho ViewPager2 (MyAdapter.java)
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
public class MyAdapter extends FragmentStateAdapter {
private static final int TAB_COUNT = 3;
public MyAdapter(FragmentActivity fa) {
super(fa);
}
@Override
public Fragment createFragment(int position) {
switch (position) {
case 0: return new FootballFragment();
case 1: return new CricketFragment();
case 2: return new NbaFragment();
default: return new FootballFragment();
}
}
@Override
public int getItemCount() {
return TAB_COUNT;
}
}
Bước 6: Tạo 3 Fragment
Click chuột phải package → New → Fragment → Fragment (Blank)
a) FootballFragment.java
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class FootballFragment extends Fragment {
public FootballFragment() {}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_football, container, false);
}
}
fragment_football.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="⚽ Football Fragment"
android:textSize="24sp"
android:textStyle="bold" />
</FrameLayout>
b) CricketFragment.java / fragment_cricket.xml
// Java: CricketFragment.java - tương tự, return R.layout.fragment_cricket // XML: fragment_cricket.xml - TextView "🏏 Cricket Fragment"
c) NbaFragment.java / fragment_nba.xml
// Java: NbaFragment.java - tương tự, return R.layout.fragment_nba // XML: fragment_nba.xml - TextView "🏀 NBA Fragment"
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.tablayoutdemo">
<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. 3 tab hiển thị ở đầu. Vuốt ngang hoặc nhấn tab để chuyển Fragment.

TabLayoutMediator vs Cách cũ
| Cách cũ (ViewPager + TabLayout) | Cách mới (ViewPager2 + TabLayoutMediator) |
|---|---|
| PagerAdapter / FragmentPagerAdapter | FragmentStateAdapter (ViewPager2) |
| viewPager.addOnPageChangeListener | Tự động sync qua Mediator |
| tabLayout.addOnTabSelectedListener | Tự động sync qua Mediator |
| setOffscreenPageLimit thủ công | Mặc định cache tốt hơn |
| Khó RTL, vertical | Hỗ trợ RTL, vertical, diff util |
Tùy chỉnh Tab Layout
1. Tab với Icon
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
tab.setText(titles[position]);
tab.setIcon(icons[position]); // Drawable resource
}).attach();
2. Custom Tab View (Layout tùy chỉnh hoàn toàn)
tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
tabLayout.setTabMode(TabLayout.MODE_FIXED);
// Inflate custom view cho từng tab
for (int i = 0; i < tabLayout.getTabCount(); i++) {
TabLayout.Tab tab = tabLayout.getTabAt(i);
if (tab != null) {
View customView = LayoutInflater.from(this).inflate(R.layout.custom_tab, null);
TextView tv = customView.findViewById(R.id.tabText);
ImageView iv = customView.findViewById(R.id.tabIcon);
tv.setText(titles[i]);
iv.setImageResource(icons[i]);
tab.setCustomView(customView);
}
}
3. Scrollable Tabs (nhiều tab)
app:tabMode="scrollable" // Thay vì fixed
Tóm tắt
- Dùng ViewPager2 + TabLayoutMediator (Material Components 1.1+)
- Adapter kế thừa FragmentStateAdapter
- FragmentStateAdapter tự động hủy Fragment không hiển thị (tiết kiệm bộ nhớ)
- TabLayout thuộc AppBarLayout để có hiệu ứng cuộn (collapsing toolbar)
- Theme:
Theme.MaterialComponents.DayNight.NoActionBar