Use Tab with New Toolbar (Appcompat V7-21)

Use Tab with new ToolBar (AppCompat v7-21)

With the API 21 the method setNavigationMode(ActionBar.NAVIGATION_MODE_TABS) is deprecated.

UPDATE 01/08/2019 (Material Components Library)

Add the dependency to your build.gradle:

dependencies { implementation ‘com.google.android.material:material:1.1.0’ }

Then you can use the new TabLayout.

<androidx.constraintlayout.widget.ConstraintLayout>

<com.google.android.material.appbar.AppBarLayout ...>

<androidx.appcompat.widget.Toolbar .../>

<com.google.android.material.tabs.TabLayout
...
/>

</com.google.android.material.appbar.AppBarLayout>

<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</androidx.constraintlayout.widget.ConstraintLayout>

The code is simple:

TabLayout tabs = (TabLayout) findViewById(R.id.tabs);
tabs.setupWithViewPager(pager);

UPDATE 29/05/2015 (Support Library)

With the new Design Support Library now you can use the TabLayout.

Just add this dependency to your build.gradle

compile 'com.android.support:design:22.2.0'

The code is very simple:

TabLayout tabLayout = (TabLayout) findViewById(R.id.tabs);
tabLayout.setupWithViewPager(viewPager);

To implement many of the features of material designs you should use it within a
CoordinatorLayout and a AppBarLayout.

Something like this:

 <android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<android.support.design.widget.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent">

<android.support.v7.widget.Toolbar
...
app:layout_scrollFlags="scroll|enterAlways"/>

<android.support.design.widget.TabLayout
...
app:layout_scrollFlags="scroll|enterAlways"/>

</android.support.design.widget.AppBarLayout>

<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />

</android.support.design.widget.CoordinatorLayout>

OLD

You can use a different pattern. For example you can use the same example that you can see in googleio14.

It uses a SlidingTabLayout which works with a ViewPager.

Here you can find the example (it is in your sdk example)

Here you can find the Google io14 example:

  • Layout

  • Java

Use Tab with new ToolBar (AppCompat v7-21) in mvvmcross

I works just the same as normal Android apps. Use the layouts that Gabriele Mariotti's link has. To make the viewpager work with bindings in MvvmCross you need to use something like this: https://github.com/MvvmCross/MvvmCross-AndroidSupport/blob/master/Cirrious.MvvmCross.Droid.Support.V4/MvxFragmentStatePagerAdapter.cs

For better readability: https://gist.github.com/martijn00/23b00172af9e2c798f3d

Here is some code:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/main_content"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
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:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:layout_scrollFlags="scroll|enterAlways" />
<android.support.design.widget.TabLayout
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="16dp"
app:tabGravity="center"
app:tabMode="scrollable" />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="fill_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

public class SomeFragment : MvxFragment<SomeViewModel>
{
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var view = base.OnCreateView(inflater, container, savedInstanceState);

var viewPager = view.FindViewById<Android.Support.V4.View.ViewPager>(Resource.Id.viewpager);
if (viewPager != null)
{
var fragments = new List<MvxViewPagerFragmentAdapter.FragmentInfo>
{
new MvxViewPagerFragmentAdapter.FragmentInfo
{
FragmentType = typeof(SomeFragment1),
Title = "",
ViewModel = ViewModel.ViewModelSomething1
},
new MvxViewPagerFragmentAdapter.FragmentInfo
{
FragmentType = typeof(SomeFragment2),
Title = ViewModel.ViewModelPopular.TextSource.GetText("Title"),
ViewModel = ViewModel.ViewModelSomething2
},
new MvxViewPagerFragmentAdapter.FragmentInfo
{
FragmentType = typeof(SomeFragment3),
Title = ViewModel.ViewModelContributors.TextSource.GetText("Title"),
ViewModel = ViewModel.ViewModelSomething3
}
};
viewPager.Adapter = new MvxViewPagerFragmentAdapter(Activity, Activity.SupportFragmentManager, fragments);
}

var tabLayout = view.FindViewById<TabLayout>(Resource.Id.tabs);
tabLayout.SetupWithViewPager(viewPager);

return view;
}
}

public class MvxFragmentStatePagerAdapter
: FragmentStatePagerAdapter
{
private readonly Context _context;

public IEnumerable<FragmentInfo> Fragments { get; private set; }

public override int Count
{
get { return Fragments.Count(); }
}

protected MvxFragmentStatePagerAdapter(IntPtr javaReference, JniHandleOwnership transfer)
: base(javaReference, transfer)
{
}

public MvxFragmentStatePagerAdapter(
Context context, FragmentManager fragmentManager, IEnumerable<FragmentInfo> fragments)
: base(fragmentManager)
{
_context = context;
Fragments = fragments;
}

public override Fragment GetItem(int position)
{
var fragmentInfo = Fragments.ElementAt(position);
var fragment = Fragment.Instantiate(_context,
FragmentJavaName(fragmentInfo.FragmentType));
((MvxFragment)fragment).ViewModel = fragmentInfo.ViewModel;
return fragment;
}

protected static string FragmentJavaName(Type fragmentType)
{
var namespaceText = fragmentType.Namespace ?? "";
if (namespaceText.Length > 0)
namespaceText = namespaceText.ToLowerInvariant() + ".";
return namespaceText + fragmentType.Name;
}

public override ICharSequence GetPageTitleFormatted(int position)
{
return new Java.Lang.String(Fragments.ElementAt(position).Title);
}

public class FragmentInfo
{
public string Title { get; set; }

public Type FragmentType { get; set; }

public IMvxViewModel ViewModel { get; set; }
}
}

how to set NAVIGATION_MODE_LIST on Toolbar new appcompat v7 21

With the API 21 the method setNavigationMode(ActionBar.NAVIGATION_MODE_LIST) is deprecated.

The best way to work with a spinner is to use a Toolbar like this:

<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_actionbar"
android:layout_height="?attr/actionBarSize"
android:layout_width="match_parent"
android:background="?attr/colorPrimary">

<Spinner
android:id="@+id/spinner_toolbar"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />

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

You can find an example in the Google IO 2014

Using Sliding Tabs with Toolbar

So after a few days of lots of research, and looking through GitHub, I finally managed to solve my problem.

Steps to updating the ActionBar tabs to Toolbar tabs using AppCompatActivity:



UPDATE: After Friday 29th May 2015:

Thankfully, using a TabLayout with the Toolbar has become much simpler since the announcement of the Android Design Support Library in Google I/O 2015.

We no longer need to download custom view classes, and this is something Google really should have done a long time ago.

From the Android Developers' Blogspot post on the Android Design Support Library:

Tabs:

Switching between different views in your app via tabs is not a new concept to material design and they are equally at home as a top level navigation pattern or for organizing different groupings of content within your app (say, different genres of music).

Sample Image

The Design library’s TabLayout implements both fixed tabs, where the view’s width is divided equally between all of the tabs, as well as scrollable tabs, where the tabs are not a uniform size and can scroll horizontally. Tabs can be added programmatically:

TabLayout tabLayout = ...;

tabLayout.addTab(tabLayout.newTab().setText("Tab 1"));

However, if you are using a ViewPager for horizontal paging between tabs, you can create tabs directly from your PagerAdapter’s getPageTitle() and then connect the two together using setupWithViewPager(). This ensures that tab selection events update the ViewPager and page changes update the selected tab.



Prior to Google I/O 2015:

Firstly, I downloaded the SlidingTabLayout.java and SlidingTabStrip.java files from Google's I/O Conference app on GitHub. These would be the views that would be used in the tab layout, so I created a folder with my other Java activities called 'view' and placed them there.

Next, I edited my activity layout .xml to look a bit like this:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.mycompany.myapp.MyActivity" >

<!-- This is the Toolbar with the tabs underneath -->
<LinearLayout android:id="@+id/detail_headerBar"
style="@style/HeaderBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<include android:id="@+id/detail_toolbar" layout="@layout/toolbar" />

<com.mycompany.myapp.view.SlidingTabLayout
android:id="@+id/sliding_tabs"
android:background="?attr/colorPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

<!-- This is the ViewPager (which I had used before) and
it would be responsible for the swiping to change layouts -->
<android.support.v4.view.ViewPager
android:id="@+id/view_pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/detail_headerBar"
android:layout_above="@+id/detail_adView" />

<!-- I also had an AdView in my layout,
but this is not necessary for creating tab layouts -->
<com.google.android.gms.ads.AdView
android:id="@+id/detail_adView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
ads:adSize="SMART_BANNER"
ads:adUnitId="@string/banner_ad_unit_id" >
</com.google.android.gms.ads.AdView>

</RelativeLayout>

The line which references the Toolbar (<include android:id="@+id/detail_toolbar" layout="@layout/toolbar" />), is referencing the following layout (for those who aren't sure how to use the Toolbar yet):

<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/toolbar"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />

And in both of the .xml layout files above, ?attr/colorPrimary, refers to the primary colour of my app (which I had defined in a style).

Also, in the first layout, the style I had mentioned as @style/HeaderBar refers to the following:

<style name="HeaderBar">
<item name="android:background">?colorPrimary</item>
<item name="android:elevation">4dp</item>
<!-- You may have to override this in a v21 version of this file -->
</style>

Before I started setting up the layouts in Java, I had to make sure to change the package names in SlidingTabLayout.java and SlidingTabStrip.java corresponding to where they were placed. In my case, I used: package com.mycompany.myapp.view; in both of these files.

Now, in my Activity (which was extending AppCompatActivity), I first added the following in the onCreate method:

Toolbar toolbar = (Toolbar) findViewById(R.id.detail_toolbar);
setSupportActionBar(toolbar);

This would be reponsible for displaying the Toolbar.

Then I setup the ViewPager and SlidingTabLayout parts:

mViewPager = (ViewPager) findViewById(R.id.view_pager);
mViewPager.setAdapter(new ViewPagerAdapter(getSupportFragmentManager()));

mSlidingTabLayout = (SlidingTabLayout) findViewById(R.id.sliding_tabs);
mSlidingTabLayout.setSelectedIndicatorColors(getResources().getColor(R.color.tab_line));
mSlidingTabLayout.setDistributeEvenly(true);
mSlidingTabLayout.setViewPager(mViewPager);

The colour 'tab_line' was a colour I had declared in color.xml which would be the colour of the tab line indicator. Also note that the variables above were global which I defined previously in this activity:

SlidingTabLayout mSlidingTabLayout;
ViewPager mViewPager;

The final thing to do was to setup the ViewPagerAdapter which I had called eariler. This would be responsible for changing the page depending on which tab was selected. I used the following:

public class ViewPagerAdapter extends FragmentPagerAdapter {

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

@Override
public int getCount() {
// Returns the number of tabs
return 3;
}

@Override
public Fragment getItem(int position) {
// Returns a new instance of the fragment
switch (position) {
case 0:
return new FragmentOne();
case 1:
return new FragmentTwo();
case 2:
return new FragmentThree();
}
return null;
}

@Override
public CharSequence getPageTitle(int position) {
Locale l = Locale.getDefault();
switch (position) {
case 0:
return getString(R.string.title_section1).toUpperCase(l);
case 1:
return getString(R.string.title_section2).toUpperCase(l);
case 2:
return getString(R.string.title_section3).toUpperCase(l);
}
return null;
}
}

I hope this was a thorough enough answer for those who are having the same trouble as I did, when switching from ActionBarActivity to AppCompatActivity and starting to use Toolbar instead of ActionBar. If there is anything that is unclear, feel free to comment below.

Action bar navigation modes are deprecated in Android L

The new Android Design Support Library adds TabLayout, providing a tab implementation that matches the material design guidelines for tabs. A complete walkthrough of how to implement Tabs and ViewPager can be found in this video

Now deprecated: The PagerTabStrip is part of the support library (and has been for some time) and serves as a direct replacement. If you prefer the newer Google Play style tabs, you can use the PagerSlidingTabStrip library or modify either of the Google provided examples SlidingTabsBasic or SlidingTabsColors as explained in this Dev Bytes video.



Related Topics



Leave a reply



Submit