Android ViewPager – Sliding Tabs With ListViews

Read-only properties in JavaFX 8

Android ViewPager – Sliding Tabs With ListViews







Android ViewPager Sliding Tabs Tutorial.

Introduction

Swiping is cool,I have said it before.And there is one android support library class that makes it easy to implement in our apps,the ViewPager.This class was added in Android 4.0 to android.support.v4 libraries.ViewPager itself is a view,but a unique one.For one you won't be interacting with viewpager as you do with widgets.Its purpose,togethher with its elder brother,the FragmentPagerAdapter and FragmentSupportPagerAdapter,are to help in paging,as the name Viewpager suggests.Secondly,Viewpager isn't added via UI designer like widgets,perhaps because it was added later on and must be specified with full class name tag in XML layout specification.

Here,we shall see how to swipe through fragments.We'll have a total of three fragments.These fragments shall have their own view hierarchy.Hence we shall add ListView component in each of them.These ListViews shall be populated with different data sets.We shal then navigate through them either by swiping or by using material clickable tabs.

What we do :

  • Show Material Tablayout tabs in our android app.
  • The tabs shall be used for navigation by clicking.
  • When clicked we show a fragment.
  • We'll have three fragments in this tutorial.They'll contain simple imageviews.
  • To use fragments as our pages we need FragmentPagerAdapter.
  • It helps in binding our pages/fragments to our tabs.
  • FragmentPageAdapter belongs to support.v4 libraries.

What You do :

  • Create a project in android studio.
  • Give it a name and choose minimum and target SDKs.

This is an android Swipe Tabs tutorial.We use Material desing toolbar and viewpager.Our fragments going to be therefore swipeable as well as clickable as a mode of navigation.The fragments going to have their individual layouts and shall contain their own unique view hierarchy.In this case we choose to show listviews ineach particular fragment.Our ListViews are custom with images and text.

Cheers.

SETUP AND DATA OBJECT

Section 1 : Our Build.Gradle

apply plugin: 'com.android.application'
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.2"
    defaultConfig {
        applicationId "com.tutorials.hp.swipetabslistview"
        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.3.0'
    compile 'com.android.support:design:23.3.0'
    compile 'com.android.support:cardview-v7:23.3.0'
}

Section 2 : Our Model Class

  • Data Object.
  • Represents a single TVShow object.
  • Each objet shall fill a single viewItem in our custom ListView.
  • Our data here represents a name and an image.
package com.tutorials.hp.swipetabslistview.mData;
/**
 * Created by Oclemmy on 5/9/2016 for ProgrammingWizards Channel and http://www.Camposha.com.
 */
public class TVShow {
    String name;
    int image;
    public TVShow(String name, int image) {
        this.name = name;
        this.image = image;
    }
    public String getName() {
        return name;
    }
    public int getImage() {
        return image;
    }
}

Our Fragments and PagerAdapter

Section 3 : CrimeFragment

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.swipetabslistview.mFragments;
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;
import android.widget.ListView;
import com.tutorials.hp.swipetabslistview.R;
import com.tutorials.hp.swipetabslistview.mData.TVShow;
import com.tutorials.hp.swipetabslistview.mListView.CustomAdapter;
import java.util.ArrayList;
/**
 * Created by Oclemmy on 5/9/2016 for ProgrammingWizards Channel and http://www.Camposha.com.
 */
public class CrimeFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView=inflater.inflate(R.layout.crime_fragment,container,false);
        ListView lv= (ListView) rootView.findViewById(R.id.crimeListView);
        CustomAdapter adapter=new CustomAdapter(this.getActivity(),getCrimeMovies());
        lv.setAdapter(adapter);
        return rootView;
    }
    private ArrayList<TVShow> getCrimeMovies() {
        //COLECTION OF CRIME MOVIES
        ArrayList<TVShow> movies=new ArrayList<>();
        //SINGLE MOVIE
        TVShow tvShow=new TVShow("BLACKLIST",R.drawable.red);
        //ADD ITR TO COLLECTION
        movies.add(tvShow);
        tvShow=new TVShow("Breaking Bad",R.drawable.breaking);
        movies.add(tvShow);
        tvShow=new TVShow("Crisis",R.drawable.crisis);
        movies.add(tvShow);
        tvShow=new TVShow("BlackList",R.drawable.blacklist);
        movies.add(tvShow);
        tvShow=new TVShow("Men In Black",R.drawable.meninblack);
        movies.add(tvShow);
        return movies;
    }
    @Override
    public String toString() {
        String title="Crime";
        return title;
    }
}

Section 4 : DramaFragment

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.swipetabslistview.mFragments;
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;
import android.widget.ListView;
import com.tutorials.hp.swipetabslistview.R;
import com.tutorials.hp.swipetabslistview.mData.TVShow;
import com.tutorials.hp.swipetabslistview.mListView.CustomAdapter;
import java.util.ArrayList;
/**
 * Created by Oclemmy on 5/9/2016 for ProgrammingWizards Channel and http://www.Camposha.com.
 */
public class DramaFrgament extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView=inflater.inflate(R.layout.drama_frgament,container,false);
        ListView lv= (ListView) rootView.findViewById(R.id.dramaListView);
        CustomAdapter adapter=new CustomAdapter(this.getActivity(),getDramaMovies());
        lv.setAdapter(adapter);
        return rootView;
    }
    private ArrayList<TVShow> getDramaMovies() {
        ArrayList<TVShow> movies=new ArrayList<>();
        TVShow tvShow=new TVShow("Star Wars",R.drawable.starwars);
        movies.add(tvShow);
        tvShow=new TVShow("Ghost Rider",R.drawable.rider);
        movies.add(tvShow);
        tvShow=new TVShow("Game Of Thrones",R.drawable.thrones);
        movies.add(tvShow);
        tvShow=new TVShow("Ghost",R.drawable.ghost);
        movies.add(tvShow);
        return movies;
    }
    @Override
    public String toString() {
        return "Drama";
    }
}

Section 5 : DocumnetaryFragment

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.swipetabslistview.mFragments;
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;
import android.widget.ListView;
import com.tutorials.hp.swipetabslistview.R;
import com.tutorials.hp.swipetabslistview.mData.TVShow;
import com.tutorials.hp.swipetabslistview.mListView.CustomAdapter;
import java.util.ArrayList;
/**
 * Created by Oclemmy on 5/9/2016 for ProgrammingWizards Channel and http://www.Camposha.com.
 */
public class DocumentaryFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView=inflater.inflate(R.layout.documentary_fragment,container,false);
        ListView lv= (ListView) rootView.findViewById(R.id.docsListView);
        CustomAdapter adapter=new CustomAdapter(this.getActivity(),getDocumentaries());
        lv.setAdapter(adapter);
        return rootView;
    }
    private ArrayList<TVShow> getDocumentaries() {
        ArrayList<TVShow> movies=new ArrayList<>();
        TVShow movie=new TVShow("Columbia",R.drawable.shuttlecarrier);
        movies.add(movie);
        movie=new TVShow("How to Live to 100",R.drawable.fruits);
        movies.add(movie);
        movie=new TVShow("Death of The Sun",R.drawable.space);
        movies.add(movie);
        movie=new TVShow("Inventions That Changed The World",R.drawable.thrones);
        movies.add(movie);
        movie=new TVShow("The Super Jumbo ",R.drawable.moderncity);
        movies.add(movie);
        return movies;
    }
    @Override
    public String toString() {
        return "Documentary";
    }
}

Section 6 : FragmentPagerAdapter

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.swipetabslistview.mFragments;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.ArrayList;
/**
 * Created by Oclemmy on 5/9/2016 for ProgrammingWizards Channel and http://www.Camposha.com.
 */
public class MyPagerAdapter extends FragmentPagerAdapter {
    ArrayList<Fragment> fragments=new ArrayList<>();
    public MyPagerAdapter(FragmentManager fm) {
        super(fm);
    }
    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }
    @Override
    public int getCount() {
        return fragments.size();
    }
    //ADD PAGE
    public void addFragment(Fragment f)
    {
        fragments.add(f);
    }
    //set title
    @Override
    public CharSequence getPageTitle(int position) {
        String title=fragments.get(position).toString();
        return title.toString();
    }
}

ListAdapter

Section 7 : CustomAdapter class

  • Bind our data set to our ListView.
  • Our row model shall get inflated here and returned as a View object.
  • We also handle our ListView Item click here.
package com.tutorials.hp.swipetabslistview.mListView;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.tutorials.hp.swipetabslistview.R;
import com.tutorials.hp.swipetabslistview.mData.TVShow;
import java.util.ArrayList;
/**
 * Created by Oclemmy on 5/9/2016 for ProgrammingWizards Channel and http://www.Camposha.com.
 */
public class CustomAdapter extends BaseAdapter {
    Context c;
    ArrayList<TVShow> tvShows;
    LayoutInflater inflater;
    public CustomAdapter(Context c, ArrayList<TVShow> tvShows) {
        this.c = c;
        this.tvShows = tvShows;
    }
    @Override
    public int getCount() {
        return tvShows.size();
    }
    @Override
    public Object getItem(int position) {
        return tvShows.get(position);
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if(inflater==null)
        {
            inflater= (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }
        if(convertView==null)
        {
            convertView=inflater.inflate(R.layout.model,parent,false);
        }
        TextView nameTxt= (TextView) convertView.findViewById(R.id.nameTxt);
        ImageView img= (ImageView) convertView.findViewById(R.id.movieImage);
        final String name=tvShows.get(position).getName();
        int image=tvShows.get(position).getImage();
        nameTxt.setText(name);
        img.setImageResource(image);
        convertView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(c,name,Toast.LENGTH_SHORT).show();
            }
        });
        return convertView;
    }
}

Main Activity

Section 8 : 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.swipetabslistview;
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.app.FragmentActivity;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.View;
import android.view.Menu;
import com.tutorials.hp.swipetabslistview.mFragments.CrimeFragment;
import com.tutorials.hp.swipetabslistview.mFragments.DocumentaryFragment;
import com.tutorials.hp.swipetabslistview.mFragments.DramaFrgament;
import com.tutorials.hp.swipetabslistview.mFragments.MyPagerAdapter;
public class MainActivity extends AppCompatActivity implements TabLayout.OnTabSelectedListener,ViewPager.OnPageChangeListener {
    ViewPager vp;
    TabLayout tabLayout;
    @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();
            }
        });
        //VIEWPAGER
        vp= (ViewPager) findViewById(R.id.mViewpager_ID);
        this.addPages();
        //TABLAYOUT
        tabLayout= (TabLayout) findViewById(R.id.mTab_ID);
        tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
        tabLayout.setupWithViewPager(vp);
        tabLayout.setOnTabSelectedListener(this);
    }
    private void addPages()
    {
        MyPagerAdapter pagerAdapter=new MyPagerAdapter(this.getSupportFragmentManager());
        pagerAdapter.addFragment(new CrimeFragment());
        pagerAdapter.addFragment(new DramaFrgament());
        pagerAdapter.addFragment(new DocumentaryFragment());
        //SET ADAPTER TO VP
        vp.setAdapter(pagerAdapter);
    }
    public void onTabSelected(TabLayout.Tab tab) {
        vp.setCurrentItem(tab.getPosition());
    }
    @Override
    public void onTabUnselected(TabLayout.Tab tab) {
    }
    @Override
    public void onTabReselected(TabLayout.Tab tab) {
    }
}

Layouts and Results

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.
  • We also add our ViewPager here.
  • Our viewpager isn't in the android.widget package hence we qualify with the full class name of the element.

 

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.swipetabslistview.MainActivity"
    tools:showIn="@layout/activity_main">
</RelativeLayout>

Model Layout

  • The model for a single row item in our custom listview.
  • Represents a single view item.
  • Has images and text.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:layout_margin="10dp"
    card_view:cardCornerRadius="10dp"
    card_view:cardElevation="10dp"
    android:layout_height="wrap_content">
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <ImageView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/movieImage"
            android:padding="10dp"
            android:src="@drawable/ghost" />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text="Name"
            android:id="@+id/nameTxt"
            android:padding="10dp"
            android:textColor="@color/colorAccent"
            android:layout_below="@+id/movieImage"
            android:layout_alignParentLeft="true"
             />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceLarge"
            android:text=" John Doe a former FBI Agent and now Physics teacher .is wrongly accussed of murdering an innocent child.He makes it his business to find the bad guys who did taht.He convinces hacker Aram to join him.....
            "
            android:id="@+id/descTxt"
            android:padding="10dp"
            android:layout_below="@+id/nameTxt"
            android:layout_alignParentLeft="true"
            />
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="TV Show"
            android:id="@+id/posTxt"
            android:padding="10dp"
            android:layout_below="@+id/movieImage"
            android:layout_alignParentRight="true" />
        <CheckBox
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/chk"
            android:layout_alignParentRight="true"
            />
    </RelativeLayout>
</android.support.v7.widget.CardView>

 

Crime Fragment 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">
    <ListView
        android:id="@+id/crimeListView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
         />
</LinearLayout>

 

Docmentary Fragment 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">
    <ListView
        android:id="@+id/docsListView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

 

Drama Fragment 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">
    <ListView
        android:id="@+id/dramaListView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>

 

 



    COMMENTS