Tab menu bar at the bottom of Android (FragmentTabHost+ViewPager+Fragment)

Keywords: Android Fragment xml Java

The bottom menu bar is frequently used in Android development. The main means of implementation are as follows:
  • TabWidget
  • Hide the TabWidget, using RadioGroup and RadioButton
  • FragmentTabHost
  • TabLayout after 5.0
  • Bottom navigation recently launched

Today, let's explore how to use Fragment+FragmentTabHost++ViewPager
Implementing the bottom menu bar

Catalog


Catalog

General design ideas

  • Fragment: Store page content with different options
  • FragmentTabHost: Click the Switch tab
  • ViewPager: Implementing left-right sliding of pages

Concept introduction

1. FragmentTabHost
Custom effects for clicking options to switch tabs

To use FragmentTabHost, you use TabHost to "load" Fragments and then put them into MainActivity.

2. ViewPager

  • Definition
    ViewPager is a class in the v4 package of the android extension package

    android.support.v4.view.ViewPager
  • Effect
    Switch the current view from left to right to achieve the effect of sliding switch.

    Note:
    1. The ViewPager class directly inherits the ViewGroup class, which, like the layout of LinearLayout, is a container in which we need to add what we want to display.
    2. The ViewPager class requires the PagerAdapter adapter class to provide data similar to ListView 3.Google officially recommends that ViewPager be used with Fragment

For specific use, please refer to another article I wrote: Android Development: Introduction to ViewPage
3. Fragment

  • Definition
    Fragment s are part of an activity's interface or an action

    1. Think of Fragment as a modular activity
    2. It has its own life cycle, receives its own events, and can be added or deleted at the activity runtime.
    3.Fragment cannot exist independently, it must be embedded in activity, and Fragment's life cycle is directly affected by its activity. For example, when activity pauses, all fragments it owns are suspended, and when activity is destroyed, all fragments it owns are destroyed.

  • Effect
    Mainly to support more dynamic and flexible interface design (introduced from 3.0)

For specific use, please refer to another article I wrote. Android development: Fragment Introduction & usage analysis

Implementation steps

  1. Define a FragmentTabHost control in the main xml layout
  2. Define the bottom menu bar layout
  3. Define each Fragment layout
  4. Define Java classes for each Fragment
  5. Define adapters to associate page cards with ViewPage
  6. Define MainActivity (see Notes for specific implementations)

Catalogue of engineering documents


Catalogue of engineering documents

Specific implementation examples

Step 1: Define a FragmentTabHost control in the main xml layout

Main XML layout: Main_tab_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

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

    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" /><!--Install 4 Fragment-->

    <FrameLayout
        android:visibility="gone"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />

    <!--Definition FragmentTabHost control-->
    <android.support.v4.app.FragmentTabHost
        android:id="@android:id/tabhost"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@android:color/black" ><!--Install 4 Fragment-->

        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_weight="0" /><!--pretend Tab Content-->
    </android.support.v4.app.FragmentTabHost>
</RelativeLayout>

Step 2: Define the bottom menu bar layout

tab_content.xml

Usually the picture is on top, the text is on the bottom.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    
android:layout_width="match_parent"    
android:layout_height="match_parent"    
android:gravity="center"   
android:orientation="vertical"    
android:background="#ffffff">    
<ImageView        
android:id="@+id/tab_imageview"        
android:layout_width="wrap_content"        
android:layout_height="wrap_content"        
/>    
<TextView        
android:id="@+id/tab_textview"        
android:layout_width="wrap_content"        
android:layout_height="wrap_content"        
android:text=""        
android:textColor="@drawable/selector_text_background" />
</LinearLayout>

Step 3: Define Fragment Layout
fragment_item1.xml&fragment_item2.xml

Two options are used here, because fragment_item1.xml is the same as fragment_item2.xml, only one is posted here.

fragment_item1.xml

<?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">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="fragment1"
        android:textSize="20sp"/>

</LinearLayout>

Step 4: Define the Java class for each Fragment

  1. Two options are used here: Fragment1. Java & fragmen2. Java
  2. Since Fragment1. Java & fragmen2. Java are the same, only one is posted here.

Fragment1.java

package com.example.carson_ho.tab_menu_demo;

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

/**
 * Created by Carson_Ho on 16/5/23.
 */
public class Fragment1 extends Fragment

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

Step 5: Define adapter associated page cards and ViewPage
MyFragmentAdapter.java

package com.example.carson_ho.tab_menu_demo;

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

import java.util.List;

/**
 * Created by Carson_Ho on 16/5/23.
 */
public class MyFragmentAdapter {extends FragmentPagerAdapter

    {

        List<Fragment> list;



        public MyFragmentAdapter(FragmentManager fm,List<Fragment> list) {
        super(fm);
        this.list=list;
    }//Write construction method to facilitate assignment calls
        @Override
        public Fragment getItem(int arg0) {
        return list.get(arg0);
    }//Return the Fragment of the corresponding location based on the location of Item, bind item and Fragment

        @Override
        public int getCount() {
        return list.size();
    }//Set the number of Item s

    }

Step 6: Define MainActivity
Specific Implementation See Annotation
MainActivity.java

package com.example.carson_ho.tab_menu_demo;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends FragmentActivity implements
        ViewPager.OnPageChangeListener, TabHost.OnTabChangeListener {

    private FragmentTabHost mTabHost;
    private LayoutInflater layoutInflater;
    private Class fragmentArray[] = { Fragment1.class, Fragment2.class };
    private int imageViewArray[] = { R.drawable.tab_home_btn, R.drawable.tab_view_btn };
    private String textViewArray[] = { "home page", "classification"};
    private List<Fragment> list = new ArrayList<Fragment>();
    private ViewPager vp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();//Initialization control
        initPage();//Initialization page
    }

    //    Control Initialization Control
    private void initView() {
        vp = (ViewPager) findViewById(R.id.pager);

        /*Implement the OnPage ChangeListener interface to monitor changes in the Tab tab and then notify the ViewPager adapter to switch the interface*/
        /*Simply put, it's for ViewPager to be able to move with the bottom menu when it's sliding.*/

        vp.addOnPageChangeListener(this);//Set up listeners for page switching
        layoutInflater = LayoutInflater.from(this);//Load Layout Manager

        /*Instantiate and bind FragmentTabHost objects*/
        mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);//Binding tahost
        mTabHost.setup(this, getSupportFragmentManager(), R.id.pager);//Bind viewpager

        /*Realize the setOnTabChangedListener interface, the purpose is to monitor the interface switching, and then realize the selected state switching of the pictures and text in TabHost.*/
        /*Simply put, the idea is that when you click on the menu below, the ViewPager above can slide to the corresponding Fragment.*/
        mTabHost.setOnTabChangedListener(this);

        int count = textViewArray.length;

        /*Create a new Tabspec tab and set the contents of the Tab menu bar and the corresponding fragments for binding*/
        for (int i = 0; i < count; i++) {
            // Set labels, icons and text for each Tab button
            TabHost.TabSpec tabSpec = mTabHost.newTabSpec(textViewArray[i])
                    .setIndicator(getTabItemView(i));
            // Add the Tab button to the Tab tab and bind Fragment
            mTabHost.addTab(tabSpec, fragmentArray[i], null);
            mTabHost.setTag(i);
            mTabHost.getTabWidget().getChildAt(i)
                    .setBackgroundResource(R.drawable.selector_tab_background);//Set Tab to change color when selected
        }
    }

    /*Initialize Fragment*/
    private void initPage() {
        Fragment1 fragment1 = new Fragment1();
        Fragment2 fragment2 = new Fragment2();

        list.add(fragment1);
        list.add(fragment2);

        //Binding Fragment adapter
        vp.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(), list));
        mTabHost.getTabWidget().setDividerDrawable(null);
    }

    private View getTabItemView(int i) {
        //Converting xml layout to view object
        View view = layoutInflater.inflate(R.layout.tab_content, null);
        //Using the view object, find the components in the layout, set the content, and then return to the view
        ImageView mImageView = (ImageView) view
                .findViewById(R.id.tab_imageview);
        TextView mTextView = (TextView) view.findViewById(R.id.tab_textview);
        mImageView.setBackgroundResource(imageViewArray[i]);
        mTextView.setText(textViewArray[i]);
        return view;
    }


    @Override
    public void onPageScrollStateChanged(int arg0) {

    }//When arg0 = 1, it means that it is sliding, when arg0 = 2, it means that it has finished sliding, and when arg0 = 0, it means that nothing has been done, that is, it stops there.

    @Override
    public void onPageScrolled(int arg0, float arg1, int arg2) {

    }//Represents the method invoked before the previous page slides to the next page

    @Override
    public void onPageSelected(int arg0) {//arg0 is the position Postion of the page you currently selected. This event is called when your page is skipped.
        TabWidget widget = mTabHost.getTabWidget();
        int oldFocusability = widget.getDescendantFocusability();
        widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);//Set View to override subclass controls to get focus directly
        mTabHost.setCurrentTab(arg0);//Set the current Tab based on location Postion
        widget.setDescendantFocusability(oldFocusability);//Set the Unpartitioning Line

    }

    @Override
    public void onTabChanged(String tabId) {//Called when Tab changes
        int position = mTabHost.getCurrentTab();
        vp.setCurrentItem(position);//Assign the location of the selected Tab to the adapter to control page switching
    }

}

Design sketch
After the six steps mentioned above, the slidable bottom menu bar is completed. The results are as follows:


Default the first Tab

Click or slide to the second Tab

Full Demo Download Address

Github of Carson_Ho: Tab_menu_Demo

Posted by laurajohn89 on Tue, 25 Dec 2018 15:06:06 -0800