پیاده سازی Tab توسط TabLayout و ViewPager متریال دیزاین

در این بخش به نحوه پیاده سازی Tab ها با استفاده از Fragment و ویجت های TabLayout و ViewPager در اندروید می پردازیم که شامل مباحث زیر می باشد:

آنچه در این آموزش می‌خوانید:

  • معرفی Tab (تب) متریال در اندروید
  • معرفی کامپوننت TabLayout
  • معرفی کامپوننت ViewPager
  • ساخت یک کلاس برای مدیریت فرگمنت ها و عنوان تب ها در ViewPager و TabLayout
  • نحوه اضافه کردن عنوان (text) به Tab ها
  • نحوه اضافه کردن آیکون به Tab ها
  • نمایش همزمان آیکون و تکست در تب ها
  • ویرایش تب ها مانند تغییر رنگ text، رنگ نوار پایین Tab و…
  • کاربرد خاصیت های tabGravity و tabMode در TabLayout

این مبحث در قالب PDF و در ۲۹ صفحه تهیه شده که در ادامه چند صفحه ی ابتدایی آن را مشاهده می کنید:

آشنایی با Tab (تب) ها در اندروید:

بنام خدا. Tab ها تقریبا در همه پلتفرم ها و برنامه ها استفاده می شوند. در سیستم عامل ویندوز وقتی یک پنجره تنظیمات را باز می کنید، در بالای پنجره چندین Tab تعبیه شده که با انتخاب هرکدام، به تعدادی از گزینه های مرتبط با عنوان آن تب دسترسی خواهید داشت. یا مثال ساده تر، در مرورگرهای وب مانند کروم و فایرفاکس، برای مشاهده هر وب سایت یک تب (Tab) جدید باز می کنیم. در سایر پلتفرم ها و نرم افزارها هم به همینصورت از Tab ها استفاده می شود. از جمله در سیستم عامل و نرم افزارهای اندروید.
اولین مثالی که به ذهنم رسید پیام رسان WhatsApp است:

مثال اپلیکیشن اندرویدی WhatsApp برای استفاده TabLayout و ViewPager

در زیر Toolbar سه Tab به نام‌های Calls، Chats و Contacts تعریف شده که با انتخاب هر یک از تب ها، محتوا و لیست مرتبط با آن نمایش داده می شود.

معرفی TabLayout در متریال دیزاین

TabLayout یکی دیگر از ویجت (کامپوننت) هایی است که اندروید در متریال دیزاین معرفی کرده و در کتابخانه design در دسترس است. با استفاده از ویجت TabLayout امکان تعریف و مدیریت Tab ها فراهم می شود (یعنی گزینه های Calls، Chats و Contacts در مثال بالا).

ViewPager چیست؟

ViewPager ویجت دیگری است که با استفاده از Fragment ها، می تواند چندین فرگمنت را در یک اکتیویتی نمایش دهد که با کشیدن صفحه به چپ یا راست و یا انتخاب Tab ها در TabLayout، فرگمنت ها به ترتیبی که تعیین کرده ایم نمایش داده می شوند (لیست چت ها، مکالمات و مخاطبین در مثال بالا).
یعنی در اپلیکیشن WhatsApp علاوه بر اینکه با لمس هریک از تب ها، به محتوای آن (یعنی فرگمنت مرتبط با آن تب) دسترسی داریم، با کشیدن فرگمنت ها به دو طرف نیز تب ها جابجا می شوند.

یک پروژه با نام Tabs ایجاد می کنم و با توجه به اینکه در زمان تهیه این آموزش، اکثر دیوایس ها از API 17 و به بالا پشتیبانی می کنند، MinSDK را روی ۱۷ تنظیم می کنم. همانطور که در ابتدا اشاره شد، لازم است کتابخانه design را به پروژه اضافه کنیم:

dependencies {

    implementation 'com.android.support:appcompat-v7:27.0.2'
    implementation 'com.android.support:design:27.0.2'
}

در مرحله اول، ActionBar پیش فرض پروژه را مطابق آنچه در آموزش تولبار بیان شد، حذف کرده و Toolbar متریال را جایگزین می کنم:

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

    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:id="@+id/m_toolbar"
        android:background="?attr/colorPrimary"
        android:elevation="3dp"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    </android.support.v7.widget.Toolbar>

</LinearLayout>

من لایه را به LinearLayout از نوع vertical تغییر دادم تا ویجت هایی که اضافه می کنم زیر یکدیگر قرار بگیرند. البته پیاده سازی با RelativeLayout یا CoordinatorLayout نیز امکان پذیر است.

MainActivity.java:

package ir.android_studio.tabs;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    Toolbar mToolbar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar =  findViewById(R.id.m_toolbar);
        setSupportActionBar(mToolbar);

    }
}

قبل از ادامه کار، پروژه را اجرا می کنم تا مطمئن شوم تولبار به اکتیویتی اضافه شده است:

اضافه کردن Toolbar به پروژه

در ادامه، چند فرگمنت ساده به پروژه اضافه می کنم:

اضافه کردن فرگمنت به پروژه اندرویدی

سه فرگمنت با نام‌های FragmentOne، FragmentTwo و FragmentThree به پروژه اضافه شد که در layout هر فرگمنت یک TextView وجود دارد. مانند fragment_one.xml:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="ir.android_studio.tabs.FragmentOne">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:text="Fragment One"
        android:textSize="30sp"/>

</FrameLayout>

مجدد main_activity.xml را باز کرده و به صورت زیر دو تگ TabLayout و ViewPager را به لایه اضافه می کنم:

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

    <android.support.v7.widget.Toolbar
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        android:id="@+id/m_toolbar"
        android:background="?attr/colorPrimary"
        android:elevation="3dp"
        app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

    </android.support.v7.widget.Toolbar>

    <android.support.design.widget.TabLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tab_layout"
        android:background="?attr/colorPrimary" />

    <android.support.v4.view.ViewPager
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/view_pager" />

</LinearLayout>

فایل colors.xml:

xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimary">#009688</color>
    <color name="colorPrimaryDark">#00796B</color>
    <color name="colorAccent">#FFC107</color>
</resources>

برای TabLayout رنگ پس زمینه یکسان با Toolbar تعریف کردم تا به صورت یکپارچه نمایش داده شوند.

TabLayout و ViewPager را در اکتیویتی تعریف می کنم:

package ir.android_studio.tabs;

import android.support.design.widget.TabLayout;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity {

    Toolbar mToolbar;
    TabLayout tbLayout;
    ViewPager vPager;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mToolbar =  findViewById(R.id.m_toolbar);
        setSupportActionBar(mToolbar);

        vPager = findViewById(R.id.view_pager);
        tbLayout = findViewById(R.id.tab_layout);

    }
}

در ادامه برای مدیریت و نمایش فرگمنت ها یک کلاس جدید با نام دلخواه ViewPagerAdapter به پروژه اضافه می کنم:

ساخت کلاس ViewPagerAdapter برای مدیریت فرگمنت ها و tabLayout

ViewPagerAdapter.java:

package ir.android_studio.tabs;


public class ViewPagerAdapter {

}

سپس این کلاس را از FragmentPagerAdapter ارث بری می کنم. FragmentPagerAdapter به یک import نیاز دارد که همانند گذشته با Alt + Enter انجام می دهم:

package ir.android_studio.tabs;

import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {

}

اندروید استودیو علامت اخطار نشان می دهد که با کلیک روی آن و انتخاب Implements Methods، به دو متد مورد نیاز FragmentPagerAdapter به کلاس اضافه می شود.

افزودن متدهای FragmentPagerAdapter

افزودن متدهای FragmentPagerAdapter

سپس اخطار دیگری می‌گیرم مبنی بر اینکه یک Constructor (متد سازنده) نیز باید اضافه شود:

اضافه کردن متد سازنده Constructor به کلاس

در نهایت کلاس به اینصورت تکمیل می شود:

package ir.android_studio.tabs;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

public class ViewPagerAdapter extends FragmentPagerAdapter {

    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return null;
    }

    @Override
    public int getCount() {
        return 0;
    }
}

من به دو List نیاز دارم. یکی برای تعریف فرگمنت ها و دیگری برای عنوان Tab ها. پس یک List از نوع Fragment با نام دلخواه frgList و یک لیست از نوع String با نام دلخواه titleList می سازم:

package ir.android_studio.tabs;

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;

import java.util.ArrayList;
import java.util.List;

public class ViewPagerAdapter extends FragmentPagerAdapter {

    private final List<Fragment> frgList = new ArrayList<>();
    private final List<String> titleList = new ArrayList<>();
    
    public ViewPagerAdapter(FragmentManager fm) {
        super(fm);
    }

    @Override
    public Fragment getItem(int position) {
        return null;
    }

    @Override
    public int getCount() {
        return 0;
    }
}

تصویر نهایی خروجی پروژه این مبحث آموزشی:

تصویر نهایی پروژه

جهت مطالعه ادامه آموزش، فایل PDF را دانلود نمائید

توجه : سورس پروژه داخل پوشه Exercises قرار داده شده است.

با توجه به اینکه آموزشهای پایه با قیمت پایین در اختیار کاربر قرار گرفته و درآمد حاصل صرف تامین هزینه های وب سایت و تهیه آموزش های آتی می شود، به اشتراک گذاری این فایل با دیگران خلاف اخلاق خواهد بود.

دانلود نسخه کامل این آموزش به همراه سورس پروژه
تعداد صفحات : ۲۹
حجم : ۲ مگابایت
قیمت : ۳ هزار تومان
توجه: صرفا در صورتی از درگاه پشتیبان استفاده کنید که قادر به پرداخت از طریق سبد دانلود نباشید.
افزودن به سبد دانلود درگاه پشتیبان
این مطلب چقدر برایتان مفید بود؟ لطفا امتیاز دهید
دوره آموزش برنامه نویسی اندروید
دوره آموزش برنامه نویسی اندروید

آموزش‌ها در دو دسته «پایه» و «تکمیلی» منتشر می‌شوند.
آموزش‌های پایه شامل مباحث اصلی و آموزش‌های تکمیلی مطالبی است که می‌بایست در کنار مطالب اصلی از آنها استفاده کنیم.
شما با دریافت این دوره به تمامی آموزش‌های غیر رایگان و رایگان موجود در وب سایت دسترسی دارید که تخفیفی برای آموزش‌های غیر رایگان نیز درنظر گرفته شده. این پکیج به دو صورت دانلودی و ارسال پستی ارائه می‌گردد.
با خرید این دوره، به تمامی آموزش‌های غیر رایگانی که در آینده منتشر می‌شود نیز به صورت رایگان دسترسی خواهید داشت!

یک دیدگاه بنویسید

پرسش‌های زیر تایید و پاسخ داده نـــخواهند شد:
۱: جزء موارد مطرح شده در صفحات مشکلات و پرسش‌های رایج و بروزرسانی‌های محتوای آموزشی باشد
۲: سوال قبلا توسط کاربران در دیدگاه‌ها مطرح و پاسخ داده شده باشد
۳: پرسش خارج از مبحث آموزشی موجود در این صفحه باشد

  • اکرم گفت:

    سلام وقت بخیر من میخام هر تب رو به یک اکتیویتی که قبلا طراحی کردم وصل کنم.از این آموزش استفاده کردم
    https://www.androidhive.info/2012/05/android-combining-tab-layout-and-list-view/
    ولی الان بهم هشدار میده کلاس TabActivity از api 13 دیگه قابل استفاده نیست و deprecate شده
    چه کنم به نظر شما؟

  • arta گفت:

    درود به شما و وقت بخیر
    من یک سوالی داشتم چرا اندروید استدیو من از یک کتابخانه ای دیگر فرگمنت استفاده می کند و نسخه ورژن ۴ کلادر لیستش نیست؟ امکانش هست راهنمایی بفرمایید؟

  • نیما گفت:

    getSupportFragmentManager()
    برای من وجود نداره مشکل کچاست؟

  • MHR گفت:

    آموزش ها عالی هست . بنده خودم از سایت خرید کردم راضی هستم .
    واسه کسایی که از قبل در این حوزه فعالیت داشتند مثل بنده متوجهد میشن
    فقط خیلی خوب بود اگه برای افراد کاملا مبتدی آموزش های جداگانه و ساده تر تهیه می شد .

  • rohollah گفت:

    سلام.
    implementation ‘com.android.support:design:27.0.2’
    رو نمیشه به گردل اضافه کرد.
    اگر میشه بگید چطور باید بنویسم با Androidx
    و همین طور اگر بگیر چطور باید کتابخونه مناسب رو پیدا کنیم و چطور از ساپورت بیایم به اندروید ایکس، ممنون میشم.

  • milad khalighi گفت:

    یه درگاه درست حسابی واسه پرداخت انتخاب میکرین
    با کارت ملت پرداخت نمیکنه میگه محدود است

  • رضا گفت:

    سلام . من توی نوشتن اپ از androidx استفاده کردم . کتابخانه material به جای design و appcompat رو هم وارد کردم . اما توی ساختن tab مشکل دارم و این خط که توی عکس زیر دورش خط کشیدم رونمیتونم اجرا کنم
    http://8upload.ir/uploads/f07249938.png
    فکر کنم فرمان توی androidx فرق داره .
    محض اطلاع فرمان ViewPagerAdapter رو نمیشناسه و قرمز نشون میده

  • مجتبی گفت:

    سلام . من یه برنامه نوشتم و داخلش ۴ تا tab داره . داخل layout یکی از تب ها ویو های زیادی استفاده شده که حدود ۱۰۰۰ خط هستش . برا همین لود برنامه سنگین شده . میخواستم ببینم چه کاری میتونم انجام بدم که این لایوت رو بشه به چنتا لایوت تقسیم کرد و همزمان اجرا بشن روی یک تب . چنتا فرگمنت ایجاد کردم ولی تا اونجایی که تو ضیحات شما رو خوندم فرگمنت ها رو روی یه فرگمنت دیگه (که همون فرگمنت تب هست) .نمیشه گذاشت چون از appcompat استخراج نشده

    • سیدمهدی مطهری گفت:

      بعید میدونم تقسیم کردن لی‌اوت بتونه تاثیر مثبتی داشته باشه. بالاخره در نهایت همه view ها اجرا میشه. نمونه سورس های رایگانی که تو وب هستند رو بررسی کنید ببینید لایه های سنگین به چه صورت پیاده سازی شده و یا اینکه چه راهکاری برای لود سریع درنظر گرفتن

  • Hjxgjm گفت:

    با سلام من تب ویو ساختم و حالا میخوام برای هر تب یه فلاتینگ اکشت باتن بزارم ولی فلاتینگ اکشن باتن به زیر صقحه میره و دیده نمیشه راه حلش چیه؟
    اینم عکساش برای درک بهتر حرفم
    http://uupload.ir/files/kr5j_screenshot_۲۰۱۹۰۵۰۲-۰۱۱۰۳۷.png
    اینم دومی . معلومه که فلاتینگ اکشن باتن بخاطر تب لیاوت مقداری رفته پایین راه چاره چیه ؟
    http://uupload.ir/files/8tyo_screenshot_۲۰۱۹۰۵۰۲-۰۱۱۰۳۵.png

  • mmilad200 گفت:

    سلام
    آیا راهی هست هنگام add کردن موارد در آرایه ، آیکون رو هم همونجا ست کرد یعنی تابعی به Adapter اضافه بشه که اینکار رو براساس شماره ایندکس و یا نام آیکون اضافه کنه ؟

  • mmilad200 گفت:

    با سلام
    دوستانی که forceclose یا stop میشه پروژشون
    باید داخل کد جاوای فرگمنت ها تمام رویدادها به جز onCreateView رو پاک کنن تا برنامه اجرا بشه

  • میلاد گفت:

    سلام
    این اموزش رو دقیقا مثل کدهایی که اورده شده انجامش دادم ولی برای من forceclose کرد.نیاز به implement داشت.واسه همین در همون mainactivity که extends شده بود از appcompact این کد رو اضافه کردم و در ایمولیتر نشون داده شد.
    public class MainActivity extends AppCompatActivity implements FragmentOne.OnFragmentInteractionListener ,FragmentTwo.OnFragmentInteractionListener, FragmentThree.OnFragmentInteractionListener{

    …………………….

    }

    گفتم شاید دوستان همچنین مشکلی واسشون پیش اومده باشه

  • Ali گفت:

    سلام
    چطور میشه وقتی وارد برنامه بشیم تب انتخابی پیش فرض روی تب وسط باشه؟

  • رضا گفت:

    با عرض سلام وتشکر به خاطر آموزش های شما
    من می خواستم به زبان فارسی تب هارو بنویسم فقط میشه بگید چطوری وقتی که میخواهیم اولین بار وارد اپلیکیشن بشیم تب انتخابی روی تب سمت راستی باشه؟

  • نادیا گفت:

    سلام من تمامی کد ها رو زدم اما در قسمت ایمپورت کردن
    import android.support.design.widget.TabLayout;
    TabLayout رو نمیشناسه

  • صالح چرخ زرین گفت:

    سلام.
    من برنامه ای دارم که مشابه آموزش شماست. appbar دارای قابلیت اسکرول هست و برای اینکه قسمت انتهایی viewpager قابل نمایش باشه یک ScrollingViewBehavior واسش نوشتم که پدینگ پایین ویوپیجر رو اصلاح می کنه. همه چیز درسته فقط نمی دونم چرا وقتی اسکرول می کنم (چه در شبیه ساز و چه در دیوایس) ، پدینگ پرش داره!!
    سوالم رو (به همراه یک سوال جانبی) در استک آورفلو هم پرسیدم که البته هنوز جواب نداره.
    اگه میشه راهنمایی کنید.
    واسه ملاحضه ی رفتار :
    https://stackoverflow.com/questions/51116794/viewpager-bottom-padding-skipping-with-custom-scrollingviewbehavior
    یه فایل گیف هم از اتفاق مورد نظر آپ کردم اونجا.
    ممنون

  • رضا گفت:

    سلام
    اقا من میخوام توی این تب بندی ها از دکمه استفاده بکنم
    دقیق همونطور که توی مین اکتیویتی انجام میدم اینجا هم انجام بدم باید چه اموزشی ببینم ؟
    دکمه بزارم و عملکرد تعریف بکنم

  • یه بنده خدا گفت:

    خداییش عالیه دستتون درد نکنه 😐
    فقط آخرش شد مثل جدایی نادر از سیمین
    کلا معلوم نشد چی شد :(((

  • amir jameh گفت:

    دستتون درد نکنه خیلی دنبال تب بندی بودم و بالاخره اینجا پیداش کردم و خریدش کردم فوق العاده کاربردی و ارزون(بهتر بگم رایگان)
    واقعا عالی بود.
    ممنون بزرگوار

  • مسعود گفت:

    سلام من این سه تب رو ساختم الان می خوام تب رو فعال کنم یعنی کلیک که روی تب شد وصل بشه به قسمت پیام کاربر چه قطعه کدی رو نیاز داره

  • علی خانی گفت:

    خیلی ممنون و متشکر.
    آموزشتون خیلی هم کاربردی و گیرا هست. من با اینکه اکثر این مفاهیم رو تو فیلم های آموزشی هم دیده بودم ولی اینجا بهتر متوجه شدم. اکثر آموزش هاتون رو هم خریدم، برای اینکه کمک ناچیزی بشه به پیشرفت سایتتون.
    متاسفانه عده ای اندک که درکی از فرهنگ ندارن، میان زیر این همه زحمت راحت یک کلام می نویسن آموزشتون بدرد نمی خوره، و گند می زنن به تمام زحمات نویسنده ی آموزش و امید کسانی که در حال یادگیری هستن رو خراب می کنن. همین امر هم باعث شده تولید علم و تولید محتوا تو کشور ما حتی تو سطوح بالای دانشگاهی تبدیل بشه به یه کپی و پیست ساده.
    متشکر

  • علی گفت:

    با این آموزش مسخرتون.
    برید به سایت های دیگه هم سربزنید بفهمید آموزش دادن یعنی چی

  • عارف گفت:

    این چه آموزشیه دیگه؟؟؟
    تا وسطاش رفتی ولش کردین؟
    اصن فرگمنت هارو تعریف نکردین به جایی وصل نکردین!!

    پس من برم بقیشو حدس بزنم

  • عبدالله گفت:

    سلام من این برنامه رو نوشتم همون همش نرم افزار اجرا نشد و بسته شد . java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.abdollah.tabs2/com.example.abdollah.tabs2.MainActivity}: java.lang.ClassCastException: android.support.design.widget.CoordinatorLayout cannot be cast to android.support.v7.widget.Toolbar
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2434)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2494)
    at android.app.ActivityThread.access$900(ActivityThread.java:153)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1347)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    این خطاهایی که داد نمیدونم چیکارش کنم ؟