ViewPager & TabLayout & Fragment 用法
1. 基本概念
1.1 ViewPager
官方描述:页面允许左右滑动的布局管理器,而不同页面带有不同的数据
ViewPager 是 V4 包中一个类
ViewPager 类直接继承了 ViewGroup 类,它是一个容器类,可以在其中添加其他的 View
类似于 ListView, 也有自己的适配器,用来填充数据页面
动态设置方法,常用的有以下几个:
setAdapter(PagerAdapter adapter)设置适配器setOffscreenPageLimit(int limit)设置缓存的页面个数,默认是1·setCureentItem(int item)跳转到特定的页面setOnPageChangeListener(...)设置页面滑动时的监听器(现在 API 中建议使用addOnPageChangeListener(...))setPageTransformer(...PageTransformer)设置页面切换时的动画效果setPageMargin(int marginPixels)设置不同页面之间的间隔setPageMarginDrawable(...)设置不同页面间隔之间的装饰图,也就是 divide,要想显示设置的图片,需要同时设置setPageMargin()
如果能够灵活运用以上几个方法,就能把 ViewPager 玩出花样了。
-
在引导页通常将 ViewPager 和 Fragment 结合使用,而像新闻分类的页面我们会再加上一个 TabLayout 三者联动使用。这时使用 PagerAdapter 就不能再满足我们的需求了,需要直接使用官方提供的专门用于与 Fragment 结合使用的 FragmentPagerAdapter。
-
FragmentPagerAdapter 将每一个页面表示为一个 Fragment,每一个 Fragment 都将保存到 FragmentManager 当中。当用户没可能再回到该页面的时候,FragmentManager 才会将这个 Fragment 销毁
-
使用 FragmentPagerAdapter 需要实现两个方法:
public Fragment getItem(int position)返回对应 Fragment 实例,一般在使用时,会通过构造传入一个要显示的 Fragment 的集合,我们只要在这儿把对应的 Fragment 返回即可public int getCount()此方法返回页面个数,只要返回传入集合的长度就行了
-
FragmentPagerAdapter 和 FragmentStatePagerAdapter 区别:
- FragmentPagerAdapter:对于不再需要的 Fragment,选择调用 onDetach() 方法,仅销毁视图,并不会销毁 Fragment 实例。
- FragmentStatePagerAdapter:会销毁不再需要的 Fragment,当当前事务提交后,会彻底的将 Fragment 从当前 Activity 的 FragmentManager 中移除,state 标明,销毁时,会将其
onSaveInstanceState(Bundle outState)中的 bundle 信息保存下来,当用户切换回来,可以通过该 bundle 恢复生成新的 Fragment。也就是说,你可以在onSaveInstanceState(Bundle outState)方法中保存一些数据,在 onCreate 中进行恢复创建 - 总结:
- 使用 FragmentStatePagerAdapter 更省内存,但是销毁后新建也需要时间。一般情况下,如果是制作主页面,仅3、4个 Tab,那么可以选择使用 FragmentPagerAdapter,如果 ViewPager 用于展示数量特别多的条目时,那么建议使用 FragmentStatePagerAdapter
1.2 TabLayout
- 定义:实现了 Material Design 效果的控件库(Android Design Support Library),提供一排横向的标签页
- 作用:用于点击选项进行切换选项卡的自定义效果(5.0可用)
- 通过
newTab()方法创建新的标签页,然后用setText()和setIcon方法分别修改标签页的文本和图标,创建完成之后,我们需要使用addTab()方法把它加到TabLayout中显示出来 - 第二种添加标签的方式是直接在 TabLayout 布局下添加 TabItem 控件
- 对于 TabLayout 在标签之前的切换事件可以通过注册一个监听器
setOnTabSelectedListener(OnTabSelectedListener) - TabLayout 通常和 ViewPager 一起使用
1.3 Fragment
fragment 是一种控制器对象,activity 可委派它执行任务。这些任务通常是管理用户界面,受管的用户界面可以是一整屏或是整屏的一部分
fragment 本身没有在屏幕上显示视图的能力。只有将它的视图放置在 activity 的视图层级结构中,fragment 视图才能显示在屏幕上
fragment 具有自己的生命周期,接受它自己的事件,并可以在 activity 运行时添加或删除
1.3.1生命周期

-
onAttach()Fragment 和 Activity 建立关联时调用(获得 activity 传递的值) -
onCreateView()为 Fragment 创建视图(加载布局)时调用(给当前的 fragment 绘制 UI 布局,可以使用线程更新 UI) -
onActivityCreated()当 Activity 中的 onCreate 方法执行完后调用(activity 执行 onCreate 方法完成了的时候会调用此方法) -
onDestroyView()Fragment 中的布局被移除时调用(表示 fragment 销毁相关联的 UI 布局) -
onDetach()Fragment 和 Activity 解除关联时调用(脱离 activity)
1.3.2 Fragment 生命周期解析
-
当一个 fragment 被创建时:
onAttach()onCreate()onCreateView()onActivityCreated()
-
当这个 fragment 对用户可见的时候,它会依次执行以下方法:
onStart()onResume()
-
当这个 fragment 进入“后台模式”的时候,依次执行以下方法:
onPause()onStop()
-
当这个 fragment 被销毁(或者说持有它的 activity 被销毁了):
-
onPause() -
onStop() -
onDestroyView() -
onDestroy() -
onDetach()
-
-
就像 Activity 一样,在以下的方法中,可以使用 Bundle 对象保存一个 fragment 对象
onCreate()onCreateView()onActivityCreated()
-
其他场景的调用
-
屏幕灭掉
onPause()onSaveInstanceState()onStop()
-
屏幕解锁
-
onStart() -
onResume()
-
-
切换到其他 fragment
onPause()onStop()onDestroyView()
-
切换回本身的 fragment
onCreateView()onActivityCreated()onStart()onResume()
-
切换到系统桌面
onPause()onSaveInstanceState()onStop()
-
回到桌面
onPause()onResume()
-
回到应用
onStart()onResume()
-
退出应用
onPause()onStop()onDestroyView()onDestroy()onDetach()
-
1.3.3 Fragment 和 Activity 生命周期对比

1.3.4 Fragment 具体使用
- 由于 Fragment 作为 Activity 一部分,所以 Fragment 的使用一般是添加到 Activity 中
- 将 Fragment 添加到 Activity 中一般有 2 种方法:
- 在 Activity 的 layout.xml 布局文件中静态添加
- 在 Activity 的 .java 文件中动态添加
1.3.4.1 方法 1 :在 Activity 的 layout.xml 布局文件中静态添加
- 创建 fragment 宿主 activity MainActivity 的布局文件 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<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" >
// 该fragment类定义在包名为"com.skywang.app"中的FragmentLayoutTest类的内部类ExampleFragment中
<fragment android:name="com.example.fragmenttest.MainActivity$ExampleFragment"
android:id="@+id/list"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
activity_main.xml
- 创建 Fragment 的布局文件 fragment_example.xml
<?xml version="1.0" encoding="utf-8"?>
<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" >
<TextView
android:text="This is a fragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
/>
</LinearLayout>
fragment_example.xml
- 创建 MainActivity.java 文件
package com.example.fragmenttest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// 继承自Fragment
// 布局文件中的Fragment通过该FragmentLayoutTest的内部类ExampleFragment实现
public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 将example_fragment.xml作为该Fragment的布局文件
// 即相当于FragmentLayoutTest直接调用fragment_example.xml来显示到Fragment中
return inflater.inflate(R.layout.fragment_example, container, false);
}
}
}
为了方便展示,将 ExampleFragment 类以静态内部类的方式定义。注意在其 layout.xml 中定义 ExampleFragment 类的准确路径
方法 1 介绍完毕
1.3.4.2 方法 2:在 Activity 的 .java 文件中动态添加
- 创建 MainActivity 的 layout.xml 文件。注意在其中定义 1 个占位符(FrameLayout),这样做的好处是:可动态在 Activity 中添加不同的 Fragment, 更加灵活
<?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:orientation="vertical" >
<FrameLayout
android:id="@+id/about_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
activity.xml
-
创建 Fragment 的布局文件,过程同方法 1
-
编写 MainActivity.java,进行 fragment 的动态添加
package com.example.fragmentdynamictest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 步骤1:获取FragmentManager
FragmentManager fragmentManager = getSupportFragmentManager();
// 步骤2:获取FragmentTransaction
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
// 步骤3:创建需要添加的Fragment :ExampleFragment
ExampleFragment fragment = new ExampleFragment();
// 步骤4:动态添加fragment
// 即将创建的fragment添加到Activity布局文件中定义的占位符中(FrameLayout)
fragmentTransaction.add(R.id.about_fragment_container, fragment);
fragmentTransaction.commit();
}
// 继承与Fragment
public static class ExampleFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// 将fragment_example.xml作为该Fragment的布局文件
return inflater.inflate(R.layout.fragment_example, container, false);
}
}
}
1.3.4.3 实现效果

2. 总体设计思路
- ViewPager:实现页面的左右滑动效果
- TabLayout:点击切换选项卡
- Fragment:存放不同选项的页面内容
3. 实现步骤
- 步骤 1:添加依赖
- 步骤 2:创建需要的 Fragment 布局文件(需要多少个 Tab 选项,就建多少个 Fragment)
- 步骤 3:创建 Tab选项需要的各个 Fragment 类
- 步骤 4:定义 Fragment 和 ViewPager 的适配器 Adapter 类
- 步骤 5:定义主布局 activity_main.xml 文件
- 步骤 6:定义 MainActivity 类
4. 具体实现
4.1 添加依赖
- 在 app 下 build.gradle 文件添加依赖
dependencies {
implementation 'com.google.android.material:material:1.0.0'
}
4.2 创建需要的 Fragment 布局文件(需要多少个 Tab 选项,就建多少个 Fragment,这里以 4 个举例)
<?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:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Fragment1"
/>
</LinearLayout>
fragment1.xml
- 一共有 4 个,这里只列举 1 个
4.3 创建 Tab选项需要的各个 Fragment 类
package com.example.topbottom_tabbar;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
public class Fragment1 extends Fragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment1, container, false);
return view;
}
}
Fragment1.java
- 一共有 4 个 fragment,只列举 1 个
- fragment 根据需要,可以在其 layout.xml 加入 RecyclerView 等控件
4.4 定义 Fragment 和 ViewPager 的适配器 Adapter 类
这个适配器类用于 Fragment 与 ViewPager 的适配,继承自 FragmentPagerAdapter 类
package com.example.topbottom_tabbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
public class FragmentAdapter extends FragmentPagerAdapter {
private String[] mTitles = new String[]{"首页", "发现", "圈子", "我的"};
public FragmentAdapter(FragmentManager fm) {
super(fm);
}
public Fragment getItem(int position) {
if(position == 1) {
return new Fragment2();
}
else if(position == 2) {
return new Fragment3();
}
else if(position == 3) {
return new Fragment4();
}
return new Fragment1();
}
public int getCount() {
return mTitles.length;
}
public CharSequence getPageTitle(int position) {
return mTitles[position];
}
}
FragmentAdapter
- 这个适配器类可根据实际情况编写方法,可以向外提供设置标题、fragment等的方法,需要灵活运用
4.5 定义主布局 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"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
>
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
>
</androidx.viewpager.widget.ViewPager>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="70dp"
android:background="#f2f2f2"
app:tabIndicatorColor="#333333"
app:tabIndicatorHeight="0dp"
app:tabMode="fixed"
app:tabSelectedTextColor="#333333"
app:tabTextAppearance="@android:style/TextAppearance.Holo.Medium"
app:tabTextColor="#CFCFCF"
/>
</LinearLayout>
activity_main.xml
- TabLayout 属性介绍
android:background:导航栏背景颜色
app:tabIndicatorColor:指示器颜色
app:tabIndicatorHeight :指示器高度
app:tabTextColor:普通状态下文字颜色
app:tabSelectedTextColor:选中时文字的颜色
app:tabMode:fixed 和 scrollable。scrollable 表示此 TabLayout 中档子 view 超出屏幕边界时候,将提供滑动以便滑出不可见的那些子 view
app:tabGravity:fill 和 center。center表示TabLayout中子 view 较少需要居中显示时候的情景
- 注意,此处实现的是 TabLayout 位于底部,ViewPager 在其上面;如果要 TabLayout 位于顶部,只需要在布局中调整它们的相对位置
4.6 定义 MainActivity 类
package com.example.topbottom_tabbar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import com.google.android.material.tabs.TabLayout;
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
private FragmentAdapter mFragmentAdapter;
private TabLayout.Tab one;
private TabLayout.Tab two;
private TabLayout.Tab three;
private TabLayout.Tab four;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//隐藏整个 ActionBar
getSupportActionBar().hide();
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
//利用适配器 mFragmentAdapter 将 ViewPager 和 Fragment 绑定在一起
mViewPager = (ViewPager) findViewById(R.id.viewPager);
mFragmentAdapter = new FragmentAdapter(getSupportFragmentManager());
mViewPager.setAdapter(mFragmentAdapter);
//将 TabLayout 和 ViewPager 绑定在一起
mTabLayout = (TabLayout) findViewById(R.id.tabLayout);
mTabLayout.setupWithViewPager(mViewPager);
//指定Tab的位置
one = mTabLayout.getTabAt(0);
two = mTabLayout.getTabAt(1);
three = mTabLayout.getTabAt(2);
four = mTabLayout.getTabAt(3);
//设置Tab的图标,假如不需要则把下面的代码删去
one.setIcon(R.mipmap.ic_launcher);
two.setIcon(R.mipmap.ic_launcher);
three.setIcon(R.mipmap.ic_launcher);
four.setIcon(R.mipmap.ic_launcher);
}
}
MainActivity.java
- 注意 ViewPager & TabLayout & Fragment 三者联动方法
- 初始化 ViewPager 和自定义 FragmentAdapter,利用 ViewPager 的
setAdapter方法,将FragmentAdapter 对象传入,完成绑定 - 初始化 TabLayout,利用 TabLayout 对象的
setupWithViewPager方法,将 ViewPager 对象传入,完成绑定 - 总结:TabLayout 对象的方法绑定 ViewPager 的对象,ViewPager 对象的方法绑定自定义 FragmentAdapter,而 FragmentAdapter 可对 Fragment 对象进行设置,从而使三者能够联动
- 初始化 ViewPager 和自定义 FragmentAdapter,利用 ViewPager 的
4.7 实现效果

本文详细介绍了ViewPager、TabLayout和Fragment在Android开发中的应用,包括基本概念、设计思路、实现步骤及具体代码示例。ViewPager实现页面滑动,TabLayout提供标签页切换,Fragment用于内容展示。
577

被折叠的 条评论
为什么被折叠?



