[JAVA] Implementation of tabs using TabLayout and ViewPager

I will post to Qiita for the first time! Until now, I have seen many people's articles and studied a lot, but I will try to write articles that will be helpful to many people, so thank you.

As for the main subject, when using TabLayout, I wanted to call the Fragment method by clicking the Toolbar menu of Activity, but I couldn't find the page that was written in an easy-to-understand manner, so I will summarize it. First, I will introduce a simple tab implementation using TabLayout and ViewPager. There are many articles that introduce the implementation of tabs, but in this article I will consider Material Design and make it. In the next article, I will summarize how to operate Fragment from Activity and how to operate Activity from Fragment.

Implementation of tabs (until display)

TabLayout This time, I will make something like Toolbar and tab integrated. By using TabLayout, tabs conforming to Material Design can be set without making detailed settings. Hide the Actionbar in style.xml, write the Toolbar in Layout, and cast a shadow on TabLayout. It is necessary to match the background color of Toolbar and TabLayout.

The height of the Toolbar's shadow (elevation) in Material Design is 4dp. You can also use @ dimen / abc_action_bar_elevation_material. Elevation & shadows - Material Design

values/styles.xml


<resources>
    <style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>
</resources>

layout/activity_main.xml


<?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="...MainActivity">

    <android.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:minHeight="?attr/actionBarSize"
        android:theme="?attr/actionBarTheme"
        app:title="Tab Sample"
        app:titleTextColor="@color/white"/>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <android.support.design.widget.TabLayout
            android:id="@+id/tabLayout"
            style="@style/MyCustomTabLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="?attr/colorPrimary"
            android:elevation="4dp" />

        <android.support.v4.view.ViewPager
            android:id="@+id/viewPager"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    </LinearLayout>
</LinearLayout>

@ style / MyCustomTabLayout is an original style that changes the text color of a tab when it is selected and when it is not selected. In Material Design, the text color of the selected tab is #fff, and the text color of the non-selected tab is #fff / opacity 70%. Tabs - Components - Material Design ARGB color code transparency summary --Qiita

values/styles.xml


<resources>
    ...

    <style name="MyCustomTabLayout" parent="Widget.Design.TabLayout">
        <item name="tabTextAppearance">@style/MyCustomTabText</item>
        <item name="tabSelectedTextColor">@color/white</item>
    </style>

    <style name="MyCustomTabText" parent="TextAppearance.AppCompat.Button">
        <item name="android:textColor">@color/white_70percent</item>
    </style>
</resources>

Fragment Next, create a Fragment. The role of Fragment when implementing tabs can accept user operations by introducing it to ViewPager via Adapter. And every time the tab selection changes, the Fragment displayed by ViewPager will switch, so you need to create as many Fragments as there are tabs. (If multiple tabs require the user to behave in the same way, one Fragment can be implemented with fewer Fragments than the number of tabs by corresponding to multiple tabs.) Fragment is similar to Activity. It consists of a class / java file and a layout / xml file. And since Fragment has a life cycle, it can be used in the same way as Activity. However, be aware that the Fragment life cycle is different from the Activity life cycle.

Main1Fragment.java


package ...;

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 Main1Fragment extends Fragment {

    public Main1Fragment() {
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main1, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

Main2Fragment.java


package ...;

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 Main2Fragment extends Fragment {

    public Main2Fragment() {
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_main2, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
    }
}

This is the basic form of Fragment. The OnCreatedView () method returns a View that inflates the Fragment Layout. Also, the onViewCreated () method can be used in the same way as the onCreate () method in Activity. Since the Override original operation is performed by super.onViewCreated (view, savedInstanceState) ;, arbitrary code is described below.

Here, change the Layout of Fragment so that the two Layouts can be distinguished. Now only change the text of the TextView.

layout/fragment_main1.xml


<LinearLayout 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"
        android:orientation="vertical"
        android:padding="16dp"
    tools:context="...Main1Fragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="fragment1" />

</LinearLayout>

layout/fragment_main2.xml


<LinearLayout 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"
        android:orientation="vertical"
        android:padding="16dp"
    tools:context="...Main2Fragment">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="fragment2" />

</LinearLayout>

Adapter Next, create an Adapter. Adapter is a mechanism for introducing Fragment into ViewPager. The Adapter that can be set in ViewPager is an adapter that inherits FragmentPagerAdapter.

OriginalFragmentPagerAdapter.java


package ...;

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

public class OriginalFragmentPagerAdapter extends FragmentPagerAdapter {

    private CharSequence[] tabTitles = {"Tab 1", "Tab 2"};

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

    @Override
    public CharSequence getPageTitle(int position) {
        return tabTitles[position];
    }

    @Override
    public Fragment getItem(int position) {
        switch (position) {
            case 0:
                return new Main1Fragment();
            case 1:
                return new Main2Fragment();
            default:
                return null;
        }
    }

    @Override
    public int getCount() {
        return tabTitles.length;
    }
}

Declare the tab title in an array of type CharSequence. getCount () method: Returns the total number of tabs. getPageTitle () method: The tab titles for the total number of tabs are reflected in the tabs. getItem () method: Reflects the Fragment corresponding to the position. Called every time you select a tab. At that time, it receives a position as an argument, so it returns the Fragment corresponding to that position. Activity Finally, it is the setting of Activity.

MainActivity.java


package ...;

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

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        OriginalFragmentPagerAdapter adapter = new OriginalFragmentPagerAdapter(getSupportFragmentManager());
        ViewPager viewPager = findViewById(R.id.viewPager);
        viewPager.setOffscreenPageLimit(2);
        viewPager.setAdapter(adapter);

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

Declare the OriginalFragmentPagerAdapter. You can create an instance by taking FragmentManager as an argument and passing getSupportFragmentManager () when declaring it. Associate ViewPager with the id of layout and set the adapter with the setAdapter () method. The setOffscreenPageLimit () method passes as an argument how many pages before the Fragment should be retained when the user changes the page of ViewPager. For example, if you set this value to 2 in ViewPager that introduced 3 Fragments, the 1st page will be regenerated when you go from page 1 to page 3 and return to page 1. Therefore, if you want to keep the value etc. and prevent it from being reloaded, you need to setOffscreenPageLimit (3). Then, TabLayout is the setupWithViewPager () method, and by setting the ViewPager with the Adapter set, when you click a tab, the Fragment corresponding to that tab will be displayed in the ViewPager.

Fragment operation

With the above, you can display the Fragment with a static layout in which the TextView is placed, and you can confirm that the Fragment of the ViewPager can be switched by operating the ViewPager and tabs. Next, it receives the user's operation in Fragment. Let's write a program that creates one EditText and one Button in the Layout of Fragment, receives a character string from EditText when the Button is clicked, and displays it in Toast.

Change the Layout of Fragment.

layout/fragment_main1.xml


<LinearLayout ...>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="fragment1" />

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="text" />

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button_Fragment1" />
</LinearLayout>

Modify the Fragment java file.

Main1Fragment.java


...

public class Main1Fragment extends Fragment {
    ...

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);

        final EditText editText = view.findViewById(R.id.editText);
        Button button = view.findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getContext(), editText.getText().toString(), Toast.LENGTH_LONG).show();
            }
        });
    }
}

To associate the View id of the Layout Layout of Fragment, write it as view.findViewById (R.id ...) in the onViewCreated () method. Since the argument view is the View returned by the OnCreatedView () method when the Fragment was created, the id can be linked from that Layout. Regarding the place where Toast is displayed, the first argument Context of makeText is getContext (). This is where you wrote MainActivity.this, this, getApplicationContext (), etc. in Activity, but you can receive the activity of the parent in which the Fragment is running by writing getContext () in Fragment.

Finally

Now you can implement the basic tabs. In the next article Activity to Fragment operation --Qiita , I would like to introduce how to call the Fragment method from Activity. I will.

Recommended Posts

Implementation of tabs using TabLayout and ViewPager
[Rails] Implementation of automatic address input using jpostal and jp_prefecture
Implementation of validation using regular expressions
Default implementation of Object.equals () and Object.hashCode ()
[Rails] Implementation of tag function using acts-as-taggable-on and tag input completion function using tag-it
[Android] Implementation of side-scrolling ListView using RecyclerView
Whereabouts of JAXB Reference implementation and DatatypeConverterImpl
Implementation of user authentication function using devise (2)
Implementation of user authentication function using devise (1)
Implementation of user authentication function using devise (3)
[Rails] Implementation of search function using gem's ransack
[Rails 6] Implementation of inquiry function using Action Mailer
[FCM] Implementation of message transmission using FCM + Spring boot
[Rails] Implementation of image enlargement function using lightbox2
Simple installation of nginx and Docker using ansible
Implementation of GKAccessPoint
[Rails] Implementation of batch processing using whenever (gem)
[Rails] Implementation of PV number ranking using impressionist
[Rails] Implementation of image slide show using Bootstrap 3
Implementation of Google Sign-In using Google OAuth 2.0 authentication (server edition)
[Rails] Implementation of drag and drop function (with effect)
[Rails] Implementation of multi-layer category function using ancestry "Preparation"
[Rails] Implementation of multi-layer category function using ancestry "seed"
[Java10] Be careful of using var and generics together
iOS app development: Timer app (5. Implementation of alarm and vibration)
Implementation of search function
Example of using vue.config.js
Applied implementation of chat-space
Summary of using FragmentArgs
Implementation of pagination function
Summary of using DBFlow
Database implementation using Realm
[Rails] Implementation of multi-layer category function using ancestry "Editing form"
Implementation of multiple word search, multiple model search, and multiple tag search (acts-as-taggable-on) of ransack
[Java] Comparison method of character strings and comparison method using regular expressions
[Rails] Implementation of tagging function using intermediate table (without Gem)
Create more Tabs and Fragments in the Fragment of BottomNavigationView
Introduction purpose of ActiveHash and simple flow to application implementation