Material design tab in xamarin android

Introduction: Here I'm adding one more UI component to Android Material Design introduction series i.e. Tab control using android material design library in xamarin android. 
Description:
According to Google doc, Tabs make it easy to explore and switch between different views or functional aspects of an app or to browse categorized data sets. Xamarin android support design library is the C# bindings for xamarin which provides the backward compatibility to number material design component up to Andriod API level 15. This Support design library should be used with theme Theme.AppCompat or inherit from Theme.AppCompat found in the AppCompat v7 Support library.

Steps 1: Prepare Prerequisites
Setup xamarin android project and Add "Xamarin Android Support Library - Design" nuget packege.

Step 2: Make the necessary changes to Styles.xml. As Support design library works only with Theme.AppCompat, App theme should be inherited from Theme.AppCompat as follows.

 <?xml version="1.0" encoding="UTF-8" ? >
 <resources  >
 <style name="DesignTheme" parent="Theme.AppCompat.Light.DarkActionBar" >
   <item name="windowNoTitle" >true </item >
      <item name="windowActionBar" >false </item >
         <item name="colorPrimary" >@color/primary </item >
         <item name="colorPrimaryDark" >@color/primary_dark </item >
         <item name="colorAccent" >@color/accent </item > </style >
 </resources >

Step 3: Accordingly Add style tag to manifest application tag theme property (android:theme="@style/DesignTheme")

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.codelog.tabbedapp">
 <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />
 <application android:allowBackup="true" android:theme="@style/DesignTheme" android:icon="@mipmap/icon" android:label="@string/app_name"></application>
</manifest>

Step 4: Now under Resource, create a folder named values-v21. Inside this create another styles.xml with the below styles.

These styles are specific to Android 5.0

<?xml version="1.0" encoding="UTF-8" ?>
<resources>
 <style name="MyTheme" parent="MyTheme.Base">
  <item name="android:windowContentTransitions">true</item>
  <item name="android:windowAllowEnterTransitionOverlap">true</item>
  <item name="android:windowAllowReturnTransitionOverlap">true</item>
  <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
  <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
 </style>
</resources>
Step 5: Open the Layout file Main.axml and add below layout code.
<?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"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/layout_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
 <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     android:id="@+id/app_bar"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:minHeight="?attr/actionBarSize"
     android:background="#ff1976d2"
     android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
     app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
    <android.support.design.widget.TabLayout
        android:id="@+id/sliding_tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ff1976d2"
        app:tabMode="fixed"
        app:tabGravity="fill" />
    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="0px"
        android:layout_weight="1"
        android:background="#ffffff" />
    </LinearLayout>
</LinearLayout> 

Step 6: Do the following changes to MainActivity.cs 
TabsFragmentPagerAdapter – Custom adapter class provides fragments required for the view pager.
SetupWithViewPager() – Assigns ViewPager to tablayout.
MainActivity.cs :

using Android.App;
using Android.Widget;
using Android.OS;
using Android.Support.V7.App; 
using Android.Support.V4.App;
using Android.Content;
using Android.Support.V7.Widget;
using Android.Support.Design.Widget;
using Android.Runtime;
using Android.Support.V4.View; 

namespace TabbedApp
{
 [Activity (Label = "TabbedApp",Icon = "@mipmap/icon")]
 public class MainActivity : FragmentActivity
 { 
  TabLayout tabLayout;
  protected override void OnCreate (Bundle savedInstanceState)
  {
   base.OnCreate (savedInstanceState); 
   SetContentView (Resource.Layout.Main); 
   tabLayout=FindViewById<TabLayout>(Resource.Id.sliding_tabs); 
   FnInitTabLayout (); 
  }
  void FnInitTabLayout()
  {
   tabLayout.SetTabTextColors (Android.Graphics.Color.Aqua,Android.Graphics.Color.AntiqueWhite);
   //Fragment array
   var fragments = new Android.Support.V4.App.Fragment[]
   { 
    new BlueFragment(),
    new GreenFragment(),
    new YellowFragment(), 
   }; 
   //Tab title array
   var titles = CharSequence.ArrayFromStringArray (new[] { 
    "Blue",
    "Green",
    "Yellow", 
   });

   var viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);
   //viewpager holding fragment array and tab title text
   viewPager.Adapter = new TabsFragmentPagerAdapter(SupportFragmentManager, fragments, titles);

   // Give the TabLayout the ViewPager 
   tabLayout.SetupWithViewPager(viewPager);  
  } 
 
  public void OnClick(IDialogInterface dialog, int which)
  {
   dialog.Dismiss();
  }

 } 
}
TabsFragmentPagerAdapter.cs
using System;
using Android.Support.V4.App;
using Java.Lang;

namespace TabbedApp
{
 public class TabsFragmentPagerAdapter : FragmentPagerAdapter
 {
  private readonly Fragment[] fragments;

  private readonly ICharSequence[] titles;

  public TabsFragmentPagerAdapter(FragmentManager fm, Fragment[] fragments, ICharSequence[] titles) : base(fm)
  {
   this.fragments = fragments;
   this.titles = titles;
  }
  public override int Count
  {
   get
   {
    return fragments.Length;
   }
  }

  public override Fragment GetItem(int position)
  {
   return fragments[position];
  }

  public override ICharSequence GetPageTitleFormatted(int position)
  {
   return titles[position]; 
  }
 }
}

This is the implementation steps involved in the Material design tab in xamarin android. Comment below if you find this useful or for any issues/suggestion.

More customization options: 
a) Tab title with only icon:

b) Tab title with icon and text:

c) Tab title with only text:

Explore the complete project in git with more customization options: https://github.com/suchithm/MaterialDesignTab

Reference: https://www.google.com/design/spec/components/tabs.html#
http://android-developers.blogspot.in/2015/05/android-design-support-library.html

Note: If  you are visiting this page from your employer restricted internet(proxy server)  environment then you may not get the original look of this page and code snippets.

6 comments:

  1. Why did you stop?! continue please, how to add fragments? why all tutorials are missing:(

    ReplyDelete
  2. Also how to add Toolbar in FragmentActivity?

    ReplyDelete
  3. You can explore the github link https://github.com/suchithm/MaterialDesignTab to find the complete code of fragments and setting icons

    ReplyDelete
  4. Hello friend, first thanks for your amazing job with xamarin android tutorials.
    Im trying to implement something with no luck.
    I have animage slider in the 1st tab and i want every time i swype of the image slider the other tabs fragments to be updated.

    I have try to call tabhost.invalidate() but i didnt see any changes, do you have any solution to that?
    In stuckoverflow im finding some solutions but are from java and im unable to reproduce
    Thanks

    ReplyDelete
  5. Also because i have a viewpager(for the tabs) inside a viewpager(the slider on the 1st tab) im trying to disable tab swiping when i swipe on slider.

    I have find out that in order to do what i want i have to override on Parrent ViewPager this:

    @Override
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
    if (v != this && v instanceof ViewPager) {
    return true;
    }
    return super.canScroll(v, checkV, dx, x, y);
    }
    Im not sure how to do this. I have create this class

    public class ExternalViewPager : Android.Support.V4.View.ViewPager
    {
    public ExternalViewPager(Context context, IAttributeSet attrs) : base(context, attrs)
    { }
    public ExternalViewPager(Context context) : base(context)
    { }
    protected override bool CanScroll(View vValue, bool checkV, int dx, int xValue, int yValue)
    {
    if (vValue != this && vValue.GetType() == typeof(ViewPager))
    {
    return true;
    }
    return base.CanScroll(vValue, checkV, dx, xValue, yValue);
    }

    }
    And im trying to use it like this:

    var profileviewPager = (InternalViewPager)FindViewById (Resource.Id.ProfileViewpager);

    or

    var profileviewPager = FindViewById (Resource.Id.ProfileViewpager);

    But i get errors, What i have to do? thanks

    ReplyDelete