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

猜你喜欢

转载自blog.csdn.net/qq_17846019/article/details/83987362