ViewPager&TabLayout&Fragment用法

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

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() 此方法返回页面个数,只要返回传入集合的长度就行了
  • FragmentPagerAdapterFragmentStatePagerAdapter 区别:

    • 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 布局文件中静态添加
  1. 创建 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

  1. 创建 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

  1. 创建 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 文件中动态添加
  1. 创建 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

  1. 创建 Fragment 的布局文件,过程同方法 1

  2. 编写 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 三者联动方法
    1. 初始化 ViewPager 和自定义 FragmentAdapter,利用 ViewPager 的 setAdapter 方法,将FragmentAdapter 对象传入,完成绑定
    2. 初始化 TabLayout,利用 TabLayout 对象的 setupWithViewPager 方法,将 ViewPager 对象传入,完成绑定
    3. 总结:TabLayout 对象的方法绑定 ViewPager 的对象,ViewPager 对象的方法绑定自定义 FragmentAdapter,而 FragmentAdapter 可对 Fragment 对象进行设置,从而使三者能够联动

4.7 实现效果

ViewPager&TabLayout&Fragment 用法实现效果

本文章已经生成可运行项目
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值