TabLayout is excellent user experience design component to arrange heterogeneous data in similar fashion aka categorization. Even Google Play store categorize Apps, Games, Magazines apps under tabs. Drilling down in depth Apps are categorized as Top Paid Apps, Free Apps, Trending Apps and even more as Sliding Tabs. Tabs became famous when they were introduced in Google I/O iosched application where it was implemented using SlidingTabLayout with help of viewpager component, co-ordinating the both working TabLayout was born and brought to Support library as plug and play UI component.
Download:
- When you are able categorize different types of tag containing huge amount of similar data
- Manage different options as tabs under single activity
Prerequisites:
- Android Studio with Appropriate SDK installed - Installation Steps for Ubuntu 16.04
- Android Support Repository installed via SDK manager
- Create New Android Studio project
If you're interested check out Material Design Bottom Navigation tutorial, Bottom Sheets Tutorial.
Getting Started:
compile 'com.android.support:appcompat-v7:25.2.0'
compile 'com.android.support:design:25.2.0'
compile 'com.android.support:support-v4:25.2.0'
Add these dependencies to buid.gradle file and hit the gradle sync button. Once you've synced these libraries and methods are available for you in offline.
Adding XML layout:
Setting up Tablyout for your application is pretty simple and straight forward. open your main activity.xml file and start typing the sample code given below.
Here AppBarLayout contains Toolbar and TabLayout which co-ordinates the scrolling behavior, and then Viewpager to help to manage different fragments corresponding to the tabs by managing memory efficiently.<?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="com.ivisionblog.apps.materialtabsexample.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabIndicatorColor="@color/colorAccent"
app:tabGravity="fill"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
android:background="@android:color/white" />
</LinearLayout>
Bind Fragments to Tabs:
After creating XML design layout, we need to bind layout to corresponding Fragments with Tabs using Adapter. So, we need to create TabAdapter to hold all our fragments which is used by viewpager to manage those fragments and its corresponding memory.
public class MainActivity extends AppCompatActivity {
private TabLayout tabLayout;
private ViewPager viewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar mtoolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mtoolbar);
getSupportActionBar().setTitle("Customer App");
viewPager = (ViewPager) findViewById(R.id.viewpager);
addFragmentsToViewPager(viewPager);
tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);
}
private void addFragmentsToViewPager(ViewPager viewPager) {
TabAdapter adapter = new TabAdapter(getSupportFragmentManager());
adapter.addFragment(new CustomersFragment(), "Customers");
adapter.addFragment(new ContactsFragment(), "Contacts");
viewPager.setAdapter(adapter);
}
}
TabAdapter.java:
class TabAdapter extends FragmentPagerAdapter {
private final List<Fragment> mFragmentList = new ArrayList<>();
private final List<String> mFragmentTitleList = new ArrayList<>();
public TabAdapter(FragmentManager manager) {
super(manager);
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public void addFragment(Fragment fragment, String title) {
mFragmentList.add(fragment);
mFragmentTitleList.add(title);
}
@Override
public CharSequence getPageTitle(int position) {
return mFragmentTitleList.get(position);
}
}
Thus above code maintains fragment and title as List which is extended from FragmentPagerAdapter and override the getItem and getCount method to implement. Whenever Viewpager(While swipeing or changing the tabs) requires the Fragment it calls the getItem method and which returns the Fragment to inflate into the view.
Sample Fragment:
I've added sample Fragment containing Recyclerview which is populated with Contacts data with Contacts Adapter and bind the data into the Recyclerview single contact view. The most important thing is it's good to write the recyclerview implementation in onActivityCreated method inside the fragment.
public class ContactsFragment extends Fragment {
private RecyclerView mRecyclerview;
public ContactsFragment() {
// Required empty public constructor
}
public static ContactsFragment newInstance() {
ContactsFragment fragment = new ContactsFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_contacts, container, false);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mRecyclerview = (RecyclerView) getActivity().findViewById(R.id.contactlist);
ContactsAdapter contactsAdapter = new ContactsAdapter(generateData());
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getContext());
mRecyclerview.setLayoutManager(layoutManager);
mRecyclerview.setAdapter(contactsAdapter);
}
private ArrayList<ContactsModal> generateData(){
ArrayList<ContactsModal> contactsModals = new ArrayList<>();
contactsModals.add(new ContactsModal("Midhun Vignesh S","987654321"));
contactsModals.add(new ContactsModal("Shivasurya S","987654321"));
contactsModals.add(new ContactsModal("Aswin Vayiravan","987654321"));
contactsModals.add(new ContactsModal("Muthu Alagappan M","987654321"));
contactsModals.add(new ContactsModal("SriramaMoorthy S","987654321"));
contactsModals.add(new ContactsModal("Puviyarasu V","987654321"));
contactsModals.add(new ContactsModal("Arun Kumar K R","987654321"));
contactsModals.add(new ContactsModal("Venkat Raman","987654321"));
return contactsModals;
}
}
Sample RecyclerView Adapter & Holder:
Check out the sample recyclerview adapter and holder class to support our recyclerview which is embedded in our fragment xml file.
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactsHolder> {
private ArrayList<ContactsModal> mContactsModals;
private FragmentManager mFm;
public ContactsAdapter(ArrayList<ContactsModal> contactsModals){
mContactsModals = contactsModals;
}
@Override
public ContactsHolder onCreateViewHolder(ViewGroup parent, int viewType) {
Context context = parent.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View contactView = inflater.inflate(R.layout.single_contact, parent, false);
ContactsHolder viewHolder = new ContactsHolder(contactView);
return viewHolder;
}
@Override
public void onBindViewHolder(ContactsHolder holder, int position) {
ContactsModal contact = mContactsModals.get(position);
holder.mPhoneView.setText(contact.getmPhoneNumber());
holder.mContactsNameView.setText(contact.getmName());
}
@Override
public int getItemCount() {
return mContactsModals.size();
}
public static class ContactsHolder extends RecyclerView.ViewHolder{
TextView mContactsNameView;
TextView mPhoneView;
public ContactsHolder(View itemView) {
super(itemView);
mContactsNameView = (TextView) itemView.findViewById(R.id.nameView);
mPhoneView = (TextView) itemView.findViewById(R.id.phoneNumberView);
}
}
}
And finally Fragment and single contact xml file code goes below,
<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="com.ivisionblog.apps.materialtabsexample.fragments.ContactsFragment">
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:id="@+id/contactlist"
android:layout_height="match_parent">
</android.support.v7.widget.RecyclerView>
</FrameLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:id="@+id/container"
android:layout_width="match_parent"
android:clickable="true"
android:focusable="true"
android:foreground="?android:attr/selectableItemBackground"
android:background="?android:attr/selectableItemBackground"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="0dp"
android:layout_weight="2"
android:layout_gravity="center"
android:layout_height="wrap_content">
<ImageView
android:layout_width="match_parent"
android:src="@mipmap/ic_launcher_round"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="8"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:layout_width="match_parent"
android:text="Shivasurya S"
android:textSize="18sp"
android:layout_marginTop="15dp"
android:layout_marginLeft="15dp"
android:textStyle="bold"
android:id="@+id/nameView"
android:layout_height="wrap_content" />
<TextView
android:layout_width="match_parent"
android:text="9788029400"
android:textSize="15sp"
android:layout_marginTop="10dp"
android:layout_marginLeft="15dp"
android:id="@+id/phoneNumberView"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:background="#e7e7e7"
android:layout_marginTop="5dp"
android:layout_height="3dp"/>
</LinearLayout>
Thus, We have successfully integrated Tabs with Recyclerview inside fragments in our application. If you want customization of tabs in your application you can check the table and attribute into your TabLayout xml code as app:attribute namespace
The most important properties available are listed below:
Name | Options | Description |
---|---|---|
tabBackground | @drawable/image | Background applied to the tabs |
tabGravity | center , fill | Gravity of the tabs |
tabIndicatorColor | @color/blue | Color of the tab indicator line |
tabIndicatorHeight | @dimen/tabh | Height of the tab indicator line |
tabMaxWidth | @dimen/tabmaxw | Maximum width of the tab |
tabMode | fixed , scrollable | Small number of fixed tabs or scrolling list |
tabTextColor | @color/blue | Color of the text on the tab |
Hope you have enjoyed this post, checkout official Google Android documentation for further updates in forcoming support library versions. Feel free to comment below for doubts or chat with me in Google+/Facebook or drop me e-mail for replies. Share is care.