1. 程式人生 > >Android進階:步驟四:Viewpager的基本使用

Android進階:步驟四:Viewpager的基本使用

借鑑:https://blog.csdn.net/weixin_39251617/article/details/79399592

大致內容:

ViewPager實踐的三種效果

  • 1. 引導介面 ViewPager
  • 2. FragmentPageAdapter
  • 3. 常見Tab切換效果

一、簡介

Viewpager,檢視翻頁工具,提供了多頁面切換的效果。Android 3.0後引入的一個UI控制元件,位於v4包中。低版本使用需要匯入v4包,但是現在我們開發的APP一般不再相容3.0及以下的系統版本,另外現在大多數使用Android studio進行開發,預設匯入v7包,v7包含了v4,所以不用導包,越來越方便了。

Viewpager使用起來就是我們通過建立adapter給它填充多個view,左右滑動時,切換不同的view。Google官方是建議我們使用Fragment來填充ViewPager的,這樣 可以更加方便的生成每個Page,以及管理每個Page的生命週期
 

二、基本使用

1.xml(主佈局main_acitivity.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="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

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


</RelativeLayout>

2.pager佈局(可以複用一個,也可以建立多個)我這裡寫了first...four四個佈局都是一樣的

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

    <TextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:text="first"
        android:textSize="30dp" />
</RelativeLayout>

3.MainAcitivity中

import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import com.demo.viewpagerdemo.adapter.MyPagerAdapter;

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

public class MainActivity extends AppCompatActivity {

    //全域性變數
    private ViewPager mViewPager;
    private int[] mLayoutIDs = {//每一個檢視id陣列
            R.layout.view_first,
            R.layout.view_second,
            R.layout.view_third,
            R.layout.view_four
    };
    private List<View> views;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = findViewById(R.id.id_viewpager);
        //初始化資料即檢視
        views = new ArrayList<>();
        for (int index = 0; index < mLayoutIDs.length; index++) {
            //1.構造檢視
            View view = getLayoutInflater().inflate(mLayoutIDs[index], null);
            views.add(view);
//            //2.也可以直接用圖片檢視
//            ImageView imageView = new ImageView(this);
//            imageView.setImageResource(R.mipmap.ic_launcher);
//            views.add(imageView);
        }
        //設定adapter
        mViewPager.setAdapter(new MyPagerAdapter(this, views));
        //將頁面快取不回收
        mViewPager.setOffscreenPageLimit(4);
    }

}

總結三步:

1.設定檢視源(你要展示的檢視)

2.構造介面卡(自定義MyPageraAdapter基礎PagerAdapter)

3. 設定介面卡(檢視源和元件的連線)

4.自定義介面卡

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;

import java.util.List;

public class MyPagerAdapter extends PagerAdapter {

    //全域性變數
    private Context context;
    private List<View> views;

    /**
     * 建構函式
     * 傳入上下文和檢視集合地址
     */
    public MyPagerAdapter(Context context, List<View> views) {
        //當前定義的context和views指向傳進來的
        this.context = context;
        this.views = views;
    }

    /**
     * 1.獲取view的數量
     *
     * @return
     */
    @Override
    public int getCount() {
        return views.size();
    }

    /**
     * instantiateItem方法中返回的檢視是否等於這個物件
     * 以便下次再利用
     */
    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }

    /**
     * 例項化檢視
     *
     * @param container
     * @param position
     * @return
     */
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        View child = views.get(position);//找到該位置的檢視
        container.addView(child);//將檢視加進去
        return child;//返回
    }

    /**
     * 釋放檢視
     * @param container 檢視容器
     * @param position  位置
     * @param object    物件
     */
    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        container.removeView(views.get(position));
    }

}

PageAdapter 必須重寫的四個函式:

  • int getCount()  獲取檢視數量
  • boolean isViewFromObject(View view, Object object)  判斷檢視是否為當前物件,如果是即可以重新利用
  • void destroyItem(ViewGroup container, int position,Object object) 釋放檢視避免oom
  • Object instantiateItem(ViewGroup container, int position) 例項化檢視

簡單的效果

直接載入圖片的做法:不需要建立佈局

        views = new ArrayList<>();
        for (int index = 0; index < mLayoutIDs.length; index++) {
            //直接用圖片檢視
            //1.新建一個圖片
            ImageView imageView = new ImageView(this);
            //2.給圖片設定圖片資源,如果想載入不同的圖片,可以參考載入不同佈局,設定一個圖片陣列
            imageView.setImageResource(R.mipmap.ic_launcher);
            //3.新增到list裡面去
            views.add(imageView);
        }

三、使用ViewPager實現引導頁

1.新增底部的引導點

在主佈局xml中新增一個引導點的容器Linearlayout佈局設定id為dot_layout

    <!--下方引導點的容器-->
    <LinearLayout
        android:id="@+id/dot_layout"
        android:layout_width="120dp"
        android:layout_height="30dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="30dp"
        android:gravity="center"
        android:orientation="horizontal">

    </LinearLayout>​

​

2.動態新增引導點

import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;

import com.demo.viewpagerdemo.adapter.MyPagerAdapter;

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

public class MainActivity extends AppCompatActivity {

    //全域性變數
    private ViewPager mViewPager;
    private int[] mLayoutIDs = {//每一個檢視id陣列
            R.layout.view_first,
            R.layout.view_second,
            R.layout.view_third,
            R.layout.view_four
    };
    private List<View> views;
    //裝dot的容器
    private ViewGroup mDotViewGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mViewPager = findViewById(R.id.id_viewpager);
        //初始化裝dot的容器
        mDotViewGroup = findViewById(R.id.dot_layout);
        //初始化資料即檢視
        views = new ArrayList<>();
        for (int index = 0; index < mLayoutIDs.length; index++) {
            //1.構造檢視
            View view = getLayoutInflater().inflate(mLayoutIDs[index], null);
            views.add(view);
////          //2.也可以直接用圖片檢視
//            ImageView imageView = new ImageView(this);
//            imageView.setImageResource(R.mipmap.ic_launcher);
//            views.add(imageView);

            //給dot檢視新增圖片
            ImageView dot = new ImageView(this);
            dot.setImageResource(R.mipmap.ic_launcher);

            //給每個dot通過程式碼來設定每個圖片的引數 寬高為20
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
            layoutParams.leftMargin = 20;//每個距離左邊20
            dot.setLayoutParams(layoutParams);//將這個程式碼的引數新增到dot這個圖片裡面
            dot.setEnabled(false);//不可點選

            //新增到dot檢視集合中才能顯示出來
            mDotViewGroup.addView(dot);
        }
        //設定adapter
        mViewPager.setAdapter(new MyPagerAdapter(this, views));
        //將頁面快取不回收
        mViewPager.setOffscreenPageLimit(4);
    }

}

增加一內容

1.設定dot的容器就是上面增加的linearlayout

    //裝dot的容器
    private ViewGroup mDotViewGroup;

2.oncreate中初始化

        //初始化裝dot的容器
        mDotViewGroup = findViewById(R.id.dot_layout);

 3.在迴圈中動態新增(有多少個頁面就有多少個點)

        for (int index = 0; index < mLayoutIDs.length; index++) {
            //1.構造檢視
            View view = getLayoutInflater().inflate(mLayoutIDs[index], null);
            views.add(view);

            //給dot檢視新增圖片
            ImageView dot = new ImageView(this);
            dot.setImageResource(R.mipmap.ic_launcher);

            //給每個dot通過程式碼來設定每個圖片的引數 寬高為20
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
            layoutParams.leftMargin = 20;//每個距離左邊20
            dot.setLayoutParams(layoutParams);//將這個程式碼的引數新增到dot這個圖片裡面
            dot.setEnabled(false);//不可點選

            //新增到dot檢視集合中才能顯示出來
            mDotViewGroup.addView(dot);

        }

實現效果:發現只是出現了響應的點而已,並不會隨著頁面顯示而改變,怎麼辦?往下看3

3.實現翻頁的監聽

1. 設定方法

addOnPageChangeListener()

2. 翻頁監聽介面

ViewPager.OnPageChangeListener

3. 重寫方法

onPageScrolled(int position, float positionOffset, int positionOffsetPixels)   //頁面滑動狀態停止前一直呼叫(滑動中

position:當前點選滑動頁面的位置 
positionOffset:當前頁面偏移的百分比 
positionOffsetPixels:當前頁面偏移的畫素位置

 onPageSelected(int position)    //滑動後顯示的頁面和滑動前不同,呼叫(滑動的頁面)

position:選中顯示頁面的位置

onPageScrollStateChanged(int state) //頁面狀態改變時呼叫(滑動的狀態改變)

state:當前頁面的狀態

SCROLL_STATE_IDLE:空閒狀態 
SCROLL_STATE_DRAGGING:滑動狀態 
SCROLL_STATE_SETTLING:滑動後滑翔的狀態

4. 使用

1.定義一個集合裝要顯示的dot

//設定dot的檢視資源集合
private List<ImageView> mDotViews = new ArrayList<>();

2.在上面的for迴圈中將定義好的dot裝進去

//將dot放到點集合中
mDotViews.add(dot);

3.設定滑動監聽

只用到了OnpageSelected方法

       /**
         * 滑動監聽
         */
        mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
            //頁面在滑動中
            @Override
            public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

            }
            //選中的頁面
            @Override
            public void onPageSelected(int position) {
                setDotView(position);

            }
            //頁面的狀態
            @Override
            public void onPageScrollStateChanged(int state) {
            }
        });


    }

setDotView的方法:引數是position當前的頁面的位置,如果等於原來的圖片的位置,就要更換成另外一張的圖片


    private void setDotView(int position) {
        for (int index = 0; index < mDotViews.size(); index++) {
            //當頁面滑到對應位置的圖片時,對應位置的圖片做出改變
            //使用的是三目運算子 如果==好為true執行第一個,否則執行第二個
            mDotViews.get(index).setImageResource(
                    position == index ? R.drawable.dot : R.mipmap.ic_launcher);
        }
    }

4.設定頁面初始的位置在oncreate方法中

//設定初始是展示第一頁的
mViewPager.setCurrentItem(0);
//對應的dot也是要顯示出來
setDotView(0);

實現效果:

5.拓展 翻頁動畫:開源框架ViewPagerTransforms

要想實現選款的翻頁效果

裡面有十幾種翻頁動畫,基本夠用了 
Github地址:ViewPagerTransforms

四、使用ViewPager配合Fragment

參考:https://blog.csdn.net/weixin_39251617/article/details/79399592 

與Fragment結合使用其實也一樣,只是用Fragment代替原先的View,填充Viewpager;然後就是Adapter不一樣,配合Fragment使用的有兩個Adapter:

FragmentPagerAdapterFragmentStatePagerAdapter

相同點: 
FragmentPagerAdapter和FragmentStatePagerAdapter都繼承自PagerAdapter

不同點: 
解除安裝不再需fragment時,各自採用的處理方法有所不同
 

1.FragmentStatePagerAdapter會銷燬不需要的fragment。

事務提交後, activity的FragmentManager中的fragment會被徹底移除。 FragmentStatePagerAdapter類名中的“state”表明:在銷燬fragment時,可在onSaveInstanceState(Bundle)方法中儲存fragment的Bundle資訊。使用者切換回來時,儲存的例項狀態可用來恢復生成新的fragment

2.FragmentPagerAdapter有不同的做法。

對於不再需要的fragment, FragmentPagerAdapter會選擇呼叫事務的detach(Fragment)方法來處理它,而非remove(Fragment)方法。也就是說, FragmentPagerAdapter只是銷燬了fragment的檢視, fragment例項還保留在FragmentManager中。因此,FragmentPagerAdapter建立的fragment永遠不會被銷燬

也就是:在destroyItem()方法中,FragmentStatePagerAdapter呼叫的是remove()方法,適用於頁面較多的情況;FragmentPagerAdapter呼叫的是detach()方法,適用於頁面較少的情況。但是有頁面資料需要重新整理的情況,不管是頁面少還是多,還是要用FragmentStatePagerAdapter,否則頁面會因為沒有重建得不到重新整理

3.簡單使用 

1.主頁面佈局xml fragment_viewpager.xml

<?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.support.v4.view.ViewPager
    android:id="@+id/id_fragment_viewpager"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

</android.support.v4.view.ViewPager>
</LinearLayout>

2.fragment的fragment_test.xml佈局

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

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:text="我是fragment"
        android:textSize="36dp" />
</RelativeLayout>

3.Fragment建立的程式碼 TestFragment.java

import android.os.Bundle;
import android.support.annotation.NonNull;
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 TestFragment extends Fragment {
    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_test, null);
        return view;
    }
}

4.主介面程式碼TabViewPagerAdapter.java


import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;

public class TabViewPagerAdapter extends AppCompatActivity {

    private ViewPager viewPager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_viewpager);
        viewPager = findViewById(R.id.id_fragment_viewpager);
        //設定 介面卡
        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager())
        {
            @Override
            public Fragment getItem(int position) {
                //這是自定義的fragment
                return new TestFragment();
            }

            @Override
            public int getCount() {
                //定義數量
                return 4;
            }
        });

    }
}

 這樣就可以實現了

效果:

5.給fragment傳值

每次的頁面都是一樣的,怎麼在不同的頁面顯示不同的東西呢?

簡單實現:將每個fragment裡面的textview顯示當前的position

1.在FragmentPagerAdapter的getItem(int position)將position傳到Fragment裡面去顯示

2.不建議直接在new testFragment()中傳

3.在TestFragment中寫一個獲取Fragment例項的靜態方法,同時將position傳進去

具體實現:

TestFragment.java增加

  • 一個建立例項並傳參的方法 (setArguments)
  • 一個oncreate接受傳進來的引數(getArgument)
  • oncreate拿到引數後oncreateView顯示
public class TestFragment extends Fragment {

    public static final String POSITION = "position";
    private String position;
    private TextView fragment_tv;

    /**
     * 在主介面中獲取fragment的方法
     * 並且將position的傳進來在對應的佈局上顯示
     *
     * @param position
     * @return
     */
    public static TestFragment newInstance(int position) {
        TestFragment fragment = new TestFragment();
        Bundle b = new Bundle();
        b.putInt(POSITION, position);
        fragment.setArguments(b);
        return fragment;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //接受傳進來的值
        //setArguments 之後通過 getArguments來拿
        if (getArguments() != null) {
            //將int轉成String以便顯示
            position = String.valueOf(getArguments().getInt(POSITION));
        }

    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_test, null);
        fragment_tv = view.findViewById(R.id.fragment_tv);
        fragment_tv.setText(position);
        return view;
    }
}

 TabViewPagerAdapter.java程式碼中

設定介面卡,的 getItem方法中返回的是

TestFragment.newInstance(position); 將position傳到當前fragment中顯示了

 viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                //這是自定義的fragment
                //position是當前fragment的位置
                return TestFragment.newInstance(position);
            }

            @Override
            public int getCount() {
                //定義數量
                return 4;
            }
        });

 具體效果:

 

五、結合上面的fragment案例實現底部導航和ViewPager聯動效果

先了解一下TabHost

1. TabHost常用元件

TabWidget : 該元件就是TabHost標籤頁中上部 或者 下部的按鈕, 可以點選按鈕切換選項卡;

TabSpec : 代表了選項卡介面, 新增一個TabSpec即可新增到TabHost中;

-- 建立選項卡 : newTabSpec(String tag), 建立一個選項卡;

-- 新增選項卡 : addTab(tabSpec);

2. TabHost使用步驟

a. 定義佈局 : 在XML檔案中使用TabHost元件, 並在其中定義一個FrameLayout選項卡內容;

(下面的案例FrameLayout設定為不可見,因為它的是ViewPager,FragmentLayout就用不上了)

b. 繼承TabActivity : 顯示選項卡元件的Activity繼承TabActivity;

c. 獲取元件 : 通過呼叫getTabHost()方法, 獲取TabHost物件;

d. 建立新增選項卡 : 通過TabHost建立新增選項卡;

 

1.主佈局的xml要改變

底部的按鈕是用tabHost來實現

  • tabHost作為根部局
  • 新增tabWidget id命名要為@android:id/tabs
  • 要想tabWidget顯示還有加一個id 為@android:id/tabcontent 的FragmentLayout 設定為不可見就好
<?xml version="1.0" encoding="utf-8"?>
<TabHost 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/tab_host"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <android.support.v4.view.ViewPager
            android:id="@+id/id_fragment_viewpager"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/tab_divider">

        </android.support.v4.view.ViewPager>


        <FrameLayout
            android:id="@android:id/tabcontent"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@id/tab_divider"
            android:visibility="gone">

        </FrameLayout>

        <View
            android:id="@+id/tab_divider"
            android:layout_width="match_parent"
            android:layout_height="1dp"
            android:layout_above="@android:id/tabs"
            android:background="#000" />

        <!--tabhost 裡面包含tabwidget-->
        <!--tabwidget要想顯示必須有一個id為:
        @android:id/tabcontent的fragment-->
        <!--不設定分割線android:showDividers="none"-->
        <TabWidget
            android:id="@android:id/tabs"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:showDividers="none"
            android:layout_alignParentBottom="true">

        </TabWidget>
    </RelativeLayout>
</TabHost>

2.給每個TabWidget設定佈局

TabWidget : 該元件就是TabHost標籤頁中上部 或者 下部的按鈕, 可以點選按鈕切換選項卡;

<?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="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:gravity="center"
        android:orientation="vertical">

        <ImageView
            android:id="@+id/tab_img"
            android:layout_width="30dp"
            android:layout_height="30dp"
            android:layout_marginTop="4dp"
            android:background="@mipmap/ic_launcher" />

        <TextView
            android:id="@+id/tab_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="5dp"
            tools:text="我是標題" />

    </LinearLayout>
</RelativeLayout>

3.給標題和按鈕圖片設定selector,要實現點選下變換顏色的效果

color_tab_txt.xml 在color目錄下建立color_tab_txt.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--選中的顏色-->
    <item android:color="#4dd0c8" android:state_selected="true" />
    <!--按下的顏色-->
    <item android:color="#4dd0c8" android:state_pressed="true" />
    <!--預設的顏色-->
    <item android:color="#dddd" />
</selector>

圖片的selector:在drawable目錄下建立tab_main_icon_home.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--注意寫的順序,預設載入按順序來的-->
    <item android:drawable="@drawable/tabbar_home_pressed" android:state_selected="true" />
    <item android:drawable="@drawable/tabbar_home_pressed" android:state_pressed="true" />
    <item android:drawable="@drawable/tabbar_home" />

</selector>

 其他兩個類似

4.實現顯示到主介面上

  • 1.設定tab的標題資料、和圖片icon
  • 2.將設定好的資料利用迴圈來顯示到tab上
  • 3.實現聯動效果是tab對viewpager進行監聽和viewpager對tab進行監聽
  • 4.在TabHost新增選項卡有個setContent(this)是要實現介面的TabHost.TabContentFactory 返回一個空view即可以了
    private void initTabHost() {
        mTabHost = findViewById(R.id.tab_host);
        mTabHost.setup();
        //三個tab做出來

        //1.init data 設定標題的資料來源,我這裡定義在string裡也可以直接寫
        int[] titleIDs = {
                R.string.home,
                R.string.msg,
                R.string.me
        };
        //設定按鈕圖片的資料來源(定義好的selector)
        int[] drawableIDs = {
                R.drawable.tab_main_icon_home,
                R.drawable.tab_main_icon_msg,
                R.drawable.tab_main_icon_me
        };

        //2、 data 顯示到——>view上
        for (int index = 0; index < titleIDs.length; index++) {
            //這是每一個Tab的佈局
            //解析成view
            View view = getLayoutInflater().inflate(R.layout.tab_layout, null, false);
            ImageView icon = view.findViewById(R.id.tab_img);
            TextView title = view.findViewById(R.id.tab_title);
            //設定圖示資源
            icon.setImageResource(drawableIDs[index]);
            //設定標題資源
            title.setText(titleIDs[index]);
            //給每個Tag根部局設定背景色
            View tab = view.findViewById(R.id.tab_bg);
            tab.setBackgroundColor(getResources().getColor(R.color.white));

            //3。新增選項卡
            mTabHost.addTab(
                    mTabHost.newTabSpec(getString(titleIDs[index]))
                            .setContent(this)//要實現TabHost.TabContentFactory實現createTabContent方法
                            .setIndicator(view));

            //4.tab控制viewpager的顯示
            //點選第幾個tab就顯示第幾個viewpager
            mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
                @Override
                public void onTabChanged(String s) {
                    if (mTabHost != null) {
                        int position = mTabHost.getCurrentTab();
                        viewPager.setCurrentItem(position);
                    }
                }
            });

            //5.viewpager控制tab的顯示
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {
                    //滑動到第幾頁就第幾個tab就被選中
                    if (mTabHost != null) {
                        mTabHost.setCurrentTab(position);
                    }
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            });

        }
    }

    //返回的view就是addTab()裡面的content,這裡用不上這個view
    @Override
    public View createTabContent(String s) {
        View view = new View(this);
        return view;
    }

當然fragment也可以定義陣列來顯示(這裡變成了字串型別,之前是int型別要修改一下)

   // 三個fragment組成的viewpager

        final Fragment[] fragments = new Fragment[]{
                TestFragment.newInstance("home"),
                TestFragment.newInstance("message"),
                TestFragment.newInstance("me")
        };

返回這個陣列讓它對應就好 

 public Fragment getItem(int position) {
                return fragments[position];
            }

完整程式碼

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TextView;

public class TabViewPagerAdapter extends AppCompatActivity implements TabHost.TabContentFactory {

    private ViewPager viewPager;
    private TabHost mTabHost;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_viewpager);
        viewPager = findViewById(R.id.id_fragment_viewpager);
        //設定 介面卡
        viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                //這是自定義的fragment
                //position是當前fragment的位置
                return TestFragment.newInstance(position);
            }

            @Override
            public int getCount() {
                //定義數量
                return 4;
            }
        });
        initTabHost();

    }

    private void initTabHost() {
        mTabHost = findViewById(R.id.tab_host);
        mTabHost.setup();
        //三個tab做出來

        //1.init data 設定標題的資料來源,我這裡定義在string裡也可以直接寫
        int[] titleIDs = {
                R.string.home,
                R.string.msg,
                R.string.me
        };
        //設定按鈕圖片的資料來源(定義好的selector)
        int[] drawableIDs = {
                R.drawable.tab_main_icon_home,
                R.drawable.tab_main_icon_msg,
                R.drawable.tab_main_icon_me
        };

        //2、 data 顯示到——>view上
        for (int index = 0; index < titleIDs.length; index++) {
            //這是每一個Tab的佈局
            //解析成view
            View view = getLayoutInflater().inflate(R.layout.tab_layout, null, false);
            ImageView icon = view.findViewById(R.id.tab_img);
            TextView title = view.findViewById(R.id.tab_title);
            //設定圖示資源
            icon.setImageResource(drawableIDs[index]);
            //設定標題資源
            title.setText(titleIDs[index]);
            //給每個Tag根部局設定背景色
            View tab = view.findViewById(R.id.tab_bg);
            tab.setBackgroundColor(getResources().getColor(R.color.white));

            //3。新增選項卡
            mTabHost.addTab(
                    mTabHost.newTabSpec(getString(titleIDs[index]))
                            .setContent(this)//要實現TabHost.TabContentFactory實現createTabContent方法
                            .setIndicator(view));

            //4.tab控制viewpager的顯示
            //點選第幾個tab就顯示第幾個viewpager
            mTabHost.setOnTabChangedListener(new TabHost.OnTabChangeListener() {
                @Override
                public void onTabChanged(String s) {
                    if (mTabHost != null) {
                        int position = mTabHost.getCurrentTab();
                        viewPager.setCurrentItem(position);
                    }
                }
            });

            //5.viewpager控制tab的顯示
            viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {
                    //滑動到第幾頁就第幾個tab就被選中
                    if (mTabHost != null) {
                        mTabHost.setCurrentTab(position);
                    }
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            });

        }
    }

    //返回的view就是addTab()裡面的content,這裡用不上這個view
    @Override
    public View createTabContent(String s) {
        View view = new View(this);
        return view;
    }
}

 完成.

TabHost用起來很麻煩,推薦BottomNavigationView