Android ViewPager - Horizontal UI Navigation

android swipe tabs

Android Viewpager Swipeable tabs tutorial.

Swiping is cool.For sure.And at least almost everyone has had that experience.Unless unfortunately you live in a forest.Of which you wouldn't be reading this post.Yet there is one UI layout container introduced by Google that has made this easier now than ever.The ViewPager.The ViewPager was introduced by Google in Android 4.0. It was added to android.support.v4 libraries.

Being part of the It derives from android.view.ViewGroup. Viewpager helps us design swipeable View Objects,or pages.To facilitate this it uses a class called PagerAdapter. Infact From the name ViewPager you can guess it uses this class to manage these objects.In this scenario, or this example, replace View objects with our fragment objects.

Fragments themselves are sub-activities and powerful.They can have their own view hierarchy with viewgroups and views.In our case,we are satisfied with using Fragments with simple images as background image.Not so much fancy but the concept is the same.

Android Demo

What we do :

  • Our simple app shall have simple pages.
  • These pages shall be swipeable horizontally,left or right.
  • We make use of ViewPager class to do this.
  • Our ViewPager shall work with our FragmentPagerAdapter class.
  • Itself a subcalss of PagerAdapter.
  • But given that its so common,why don't we have also tabs.
  • Yes material tabs using Tablayout.
  • So that means the user shall either swipe or click tabs.
  • Either action shall lead him to the appropriate fragment or page.
  • We simply set the current item to the clicked tab using ViewPager's setCurrentItem() method.

Screenshot  

What You do :

  • Create a project in android studio.
  • Give it a name and choose minimum and target SDKs.
  • Personally I used 15 and 23 as visible in my build.gradle below.
  • Then choose basic activity as your template layout.
  • All these are not requirements and you can choose whatever you like.

Source Code

  Let's see the code:

1. Build.Gradle

SECTION 1 : Our Dependencies

Build.Gradle

  • Android Studio has added for us inside the dependencies closure compile statements for AppCompat and Design support libraries.
  • Note we are subclassing AppCompatActivity to make our MainActivity class an activity.
  • Design support library package gives us access to cordinatorlayout,appbar layout,and floating action button.All contained in our ActivityMain.xml layout specification.
  • No third party library are we using.

 

apply plugin: 'com.android.application'

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"

    defaultConfig {
        applicationId "com.tutorials.hp.fixedtabs"
        minSdkVersion 15
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:23.2.1'
    compile 'com.android.support:design:23.2.1'
}

 

2. Crime Fragment"

SECTION 2 : Fragments

Crime Fragment

Main Responsibility : IS OUR CRIME PAGE

  • Shall get inflated from our crime fragment layout.
  • This shall represent crime page in our app.
  • We shall show a bad boy image in this fragment.
  • Shall be shown when Crime Tab is clicked.

 

package com.tutorials.hp.fixedtabs;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class CrimeFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView=inflater.inflate(R.layout.crime_fragment,null);
        return rootView;
    }

    @Override
    public String toString() {
        return "Crime";
    }
}

 

3. Drama Fragment

Drama Fragment

Main Responsibility : IS OUR DRAMA PAGE

  • Shall get inflated from our drama fragment layout.
  • This shall represent drama page in our app.
  • We shall show a game of thrones character  image in this fragment.
  • Shall be shown when Drama Tab is clicked.
package com.tutorials.hp.fixedtabs;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class DramaFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView=inflater.inflate(R.layout.drama_fragment,null);
        return rootView;
    }

    @Override
    public String toString() {
        return "Drama";
    }
}

 

4. Documentary Fragment"

Documentary Fragment

Main Responsibility : IS OUR DOCUMENTARY PAGE

  • Shall get inflated from our documentary fragment layout.
  • This shall represent documentary page in our app.
  • We shall show a shuttle carrier plane image in this fragment.
  • Shall be shown when Documentary Tab is clicked.
package com.tutorials.hp.fixedtabs;

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class ScienceFictionFragment extends Fragment {

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View rootView=inflater.inflate(R.layout.science_fragment,null);
        return rootView;
    }

    @Override
    public String toString() {
        return "Science";
    }
}

 

5. Pager Adapter

SECTION 3 : Our Pager Adapter

FragmentPagerAdapter class.

Main Responsibility : BIND OUR FRAGMENTS TO OUR TABS.

  • Our pages we said shall be our fragments.
  • This class shall add them to our pages collection.
  • It shall also return each page when a tab is clicked.
  • We set the total count by returning the total number of fragments we have.
  • We also set the tab titles here.

 

package com.tutorials.hp.fixedtabs;

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

import java.util.ArrayList;

public class MyPagerAdapter extends FragmentPagerAdapter {

    ArrayList<Fragment> pages=new ArrayList<>();

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

    @Override
    public Fragment getItem(int position) {
        return pages.get(position);
    }

    @Override
    public int getCount() {
        return pages.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {
        return pages.get(position).toString();
    }

    public void addPage(Fragment f)
    {
        pages.add(f);
    }
}

 

6. MainActivity

SECTION 4 : Our Activity

Now here we have to make sure we reference our viewpager from our xml layout specification using the findViewById() method.Move over to activitymain.xml and add over there a viewpager definition. We said our ViewPager depends on our FragmentpagerAdapter.So instantiate the adapter and pass it to our ViewPager's setAdapter() method.

MainActivity class.

Main Responsibility : LAUNCH OUR APP.

  • It extends AppcompatActivity hence is an activity.
  • Activities are the entry point of android applications.This is no exception.
  • It loads our activity layout.
  • We shall reference the widgets like Tablayout here, and views like ViewPager,FloatingActionButton etc from our XML Layouts.
  • We then can either implement OnTabSelectedListener here explicitly on our class or just using an annonymous class.
  • We then set this listener to our tablayout.
  • Moreover we set other tablayout properties like gravity.
  • We also make sure that we instantiate our fragments and pass them to our adapter.Remember they are our pages we said.
  • Inside our annonymous class,we override some methods.
  • In this case we are only interested in OnTabSelected since we want to set the current item of our viewpager.

 

package com.tutorials.hp.fixedtabs;

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

public class MainActivity extends AppCompatActivity {

    private TabLayout tab;
    private ViewPager vp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });

        vp= (ViewPager) findViewById(R.id.viewpager);
        addPages(vp);

        tab= (TabLayout) findViewById(R.id.tabs);
        tab.setTabGravity(TabLayout.GRAVITY_FILL);
        tab.setupWithViewPager(vp);
        tab.setOnTabSelectedListener(tabSelectedListener(vp));

    }

  private void addPages(ViewPager viewPager)
  {
     MyPagerAdapter myPagerAdapter=new MyPagerAdapter(getSupportFragmentManager());
      myPagerAdapter.addPage(new CrimeFragment());
      myPagerAdapter.addPage(new DramaFragment());
      myPagerAdapter.addPage(new ScienceFictionFragment());

      vp.setAdapter(myPagerAdapter);
  }

    private TabLayout.OnTabSelectedListener tabSelectedListener(final  ViewPager pager)
    {
        return  new TabLayout.OnTabSelectedListener() {
            @Override
            public void onTabSelected(TabLayout.Tab tab) {
                pager.setCurrentItem(tab.getPosition());
            }

            @Override
            public void onTabUnselected(TabLayout.Tab tab) {

            }

            @Override
            public void onTabReselected(TabLayout.Tab tab) {

            }
        };
    }

}

   

7. ActivityMain Layout"

SECTION 5 : Our Layouts

ActivityMain.xml Layout.

  • Inflated as our activity's view.
  • Includes our content main layout.
  • Contains support.v4 widgets like Cordinatorlayout, appbarlayout, toolbar and our floating action button view.
  • Take note we also add our ViewPager here.Assign it an id cause we shall reference it from our MainActivity class.
  • Our viewpager isn't in the android.widget package hence we qualify with the full class name of the element.

 

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:context="com.tutorials.hp.fixedtabs.MainActivity">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/AppTheme.AppBarOverlay">

        <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/AppTheme.PopupOverlay" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"

           />

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

    <include layout="@layout/content_main" />

    <android.support.design.widget.FloatingActionButton
        android:id="@+id/fab"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="bottom|end"
        android:layout_margin="@dimen/fab_margin"
        android:src="@android:drawable/ic_dialog_email" />

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

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

 

8. ContentMain.xml

ContentMain.xml Layout.

  • Shall get replaced by our fragments layouts.

 

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.tutorials.hp.fixedtabs.MainActivity"
    tools:showIn="@layout/activity_main">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!" />
</RelativeLayout>

   

9. CrimeFragment.xml

CrimeFragment.xml Layout.

  • Contains Crime fragment View hierarchy.
  • Inflated to Crime fragment.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/red"
    >

</LinearLayout>

 

10. DramaFragment.xml

DramaFragment.xml Layout.

  • Contains Drama fragment View hierarchy.
  • Inflated to Drama fragment.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/breaking"
    >

</LinearLayout>

 

11. DocumentaryFragment.xml"

DocumentaryFragment.xml Layout.

  • Contains Documentary fragment View hierarchy.
  • Inflated to Documentary fragment.

 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/thrones"
    >

</LinearLayout>

12. Video/Demo"

https://www.youtube.com/watch?v=WNd6oW2uUMA

How To Run

  • Download the project above.
  • You'll get a zipped file,extract it.
  • Open the Android Studio.
  • Now close, already open project
  • From the Menu bar click on File >New> Import Project
  • Now Choose a Destination Folder, from where you want to import project.
  • Choose an Android Project.
  • Now Click on “OK“.
  • Done, your done importing the project,now edit it.

How do You Feel after reading this?

According to scientists, we humans have 8 primary innate emotions: joy, acceptance, fear, surprise, sadness, disgust, anger, and anticipation. Feel free to tell us how you feel about this article using these emotes or via the comment section. This feedback helps us gauge our progress.

Help me Grow.

I set myself some growth ambitions I desire to achieve by this year's end regarding this website and my youtube channel. Am halfway. Help me reach them by:




Recommendations


What do You Think


Previous Post Next Post