【安卓基础重点知识4】Fragment

0 阅读15分钟

一、定义

Fragment翻译为碎片,表示Activity中的行为或user interface的一部分。可以在单个Activity中组合多个Fragment来构建多窗格 UI 并在多个活动中复用Fragment

总结:

  • Fragment是依赖于 Activity的,不能独立存在的

  • 一个 Activity里可以有多个Fragment

  • 一个Fragment可以被多个 Activity 重用

  • Fragment有自己的生命周期,并能接收输入事件

  • 我们能在Activity运行时动态地添加或删除Fragment

二、优点

  • 模块化(Modularity):我们不必把所有代码全部写在Activity中,而是把代码写在各自的Fragment中

  • 可重用(Reusability):多个Activity可以重用一个Fragment

  • 可适配(Adaptability):根据硬件的屏幕尺寸、屏幕方向,能够方便地实现不同的布局,这样用户体验更好

三、生命周期

Fragment 类的代码与 Activity 非常相似。它包含与 Activity 类似的回调方法,如 onCreate()、onStart()、onPause() 和 onStop()等。实际上,如果要将现有 Android 应用转换为使用片段,可能只需将代码从 Activity 的回调方法移入片段相应的回调方法中。

1. 状态介绍

  • onAttach():当Fragment与Activity关联时调用,可以通过该方法获取并保存Activity()的引用

  • onCreate():当Fragment创建时调用,用于初始化Fragment的状态,通常用于初始化变量或加载资源

  • onCreateView():创建Fragment视图层次结构,返回Fragment的布局或视图对象

  • onActivityCreated(): 当Fragment所依附的Activity 被创建完成时调用,用于执行一些与UI 界面 相关操作

  • onStart(): Fragment可见,但还未获取焦点时调用

  • onResume(): Fragment获取焦点并开始与用户交互时调用

  • onPause(): Fragment将失去焦点并从前台转为后台时调用,通常用于暂停正在进行的操作

  • onStop(): Fragment完全不可见,处于停止状态,可以在该方法中释放资源或处理其他操作

  • onDestroyView(): 在Fragment的UI 视图被销毁时调用,通常用于清理视图相关资源

  • onDestroy(): 当Fragment销毁时调用,用于释放对象或资源

  • onDetach(): 当Fragment与Activity解除关联时调用,用于释放Activity的引用

2. 代码测试

public class StaticFragment extends Fragment {

    private static final String TAG = "JinYu";
    
    //把碎片贴到页面上
    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        Log.d(TAG, "Fragment onAttach");
    }
    //页面创建
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(TAG, "Fragment onCreate");
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        Log.d(TAG, "Fragment onCreateView");
        return inflater.inflate(R.layout.fragment_static, container, false);

    }
    //活动页面创建之后
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Log.d(TAG, "Fragment onActivityCreated");
    }
    //页面启动
    @Override
    public void onStart() {
        super.onStart();
        Log.d(TAG, "Fragment onStart");
    }
    //页面恢复
    @Override
    public void onResume() {
        super.onResume();
        Log.d(TAG, "Fragment onResume");
    }
    //页面暂停
    @Override
    public void onPause() {
        super.onPause();
        Log.d(TAG, "Fragment onPause");
    }
    //页面停止
    @Override
    public void onStop() {
        super.onStop();
        Log.d(TAG, "Fragment onStop");
    }
    //销毁碎片视图
    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.d(TAG, "Fragment onDestroyView");
    }
    //页面销毁
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "Fragment onDestroy");
    }
    //把碎片从页面撕下来
    @Override
    public void onDetach() {
        super.onDetach();
        Log.d(TAG, "Fragment onDetach");
    }
}

3. 运行结果展示

启动app

后台运行

返回app

关闭app

四、Fragment Manager详情

1. 工作原理

  • Fragment生命周期管理:FragmentManager通过管理Fragment的生命周期来控制Fragment的显示和隐藏。在Fragment生命周期中,有多个关键的阶段,例如onCreate、onCreateView、onActivityCreated、onHiddenChanged等。FragmentManager在这些关键阶段中会进行一系列的操作,例如调用Fragment的回调方法、更新 界面 、保存和恢复Fragment的状态

  • Fragment交互:FragmentManager负责处理Fragment之间的交互,例如数据传递和通信。当一个Fragment需要向另一个Fragment传递数据时,它可以通过FragmentManager调用另一个Fragment的相应方法来实现。同时,FragmentManager也提供了一些接口,允许Fragment之间进行通信,例如使用BroadcastReceiver或LocalBroadcastManager

  • Fragment事务处理:FragmentManager还负责处理Fragment的事务,即在多个操作中执行一系列的操作,并在操作完成后提交给Activity。通过Fragment事务,可以将一系列的操作打包成一个整体,方便用户进行撤销和重做操作。在执行Fragment事务时,FragmentManager会确保所有的操作都按照正确的顺序执行,并处理可能出现的异常情况。

2. 使用方法

  • 在Activity中获取FragmentManager实例:在Activity中,可以通过getSupportFragmentManager()方法获取FragmentManager实例

  • 创建和添加Fragment到Activity:使用FragmentManager实例创建和添加Fragment到Activity中,通常需要使用FragmentTransaction类来执行一系列的操作

    • FragmentTransaction主要方法

      函数名 作用 生命周期调用 注意
      add(id, fragment)
      增加framgent到队列中,并显示该fragment到指定布局中
      • 当fragment与activity连接并被建立时(onAttach()、onCreate()被调用过)onCreateView()、onActivityCreated()、onStart()、onResume()
      • 当fragment与activity未连接并未被建立时(onAttach()、onCreate()未被调用过)onAttach()、onCreate()、onCreateView()、onActivityCreated()、onStart()、onResume()
      同一个Fragmen不能增加到队列两次或多次
      show(fragment)
      显示队列中的指定framgent
      • 当队列中不存在该fragment时,回调onAttach()、onCreate()
      • 当队列中存在该fragment时并被调用过hide(fragment)时,回调onHiddenChange(boolean)
      • 其他情况没有回调函数
      replace(id, fragment) 先检查队列中是否已经存在,存在就会崩溃,不存在就会进入队列并把其他fragment清出队列,最后显示该fragment到指定布局中 同add(id, fragment)
      remove(fragment)
      销毁队列中指定的fragment
      当队列中不存在该fragment时,不会有任何反应。当队列中存在该fragment时,fragment的生命周期执行情况主要依赖是否当前fragment进入到返回栈。
      hide(fragment)
      隐藏队列中指定的fragment
      • 当队列中存在该fragment时,回调onHiddenChange(boolen)
      • 当队列中不存在该fragment时,回调onAttach()、onCreate()、onHiddenChange(boolen)
      相当于调用视图的.setVisibility(View.GONE)
      detach(fragment)
      销毁指定frament的视图
      • 当队列中存在该fragment时,回调onDestroyView()
      • 当队列中不存在该fragment时,回调onAttach()、onCreate()
      • 该fragment的onCreateView(...)不能再被调用(除非调用attach(fragment)重新连接)
      • 如果当前Activity一直存在,那么在不希望保留用户操作的时候,你可以优先使用detach
      attach(fragment)
      创建指定fragment的视图
      • 当队列中存在该fragment时且被调用detach(fragment)时,回调createView()、onActivityCreated()、onResume()
      • 当队列中不存在该fragment时,回调onAttach()、onCreate()
      • 其他情况没有用
      标识该fragment的onCreateView(……)能被调用。
      addToBackStack(string) 使本次事务增加的fragment进入当前activity的返回栈中。当前参数是对返回栈的描述,没什么实际用途。传入null即可
      commit() 提交本次事务,可在非主线程中被调用。主要用于多线程处理情况,如果有动画,等待动画加载完毕,再刷新
      commitNow() 提交本次事务,只在主线程中被调用。 这时候addToBackStack(string)不可用,如果有动画,则直接刷新,不会等待动画完毕

    • 补充:replace()和add()的区别

      • 执行replace()+addToBackStack(),切换到另一个fragment,前一个fragment的生命周期执行如下

      返回后

      • 执行replace()不加addToBackStack(),切换到另一个fragment,前一个fragment的生命周期执行如下

      • 执行add()/执行add()+addToBackStack()

      执行add(),前一个fragment的view仍然存在于页面,因此replace相当于执行了remove和add

五、静态和动态绑定fragment

1. 静态方式

新建fragment

新建Activity,在布局文件中添加

<fragment
    android:id="@+id/fragment_static"
    android:layout_width="match_parent"
    android:layout_height="60dp"
    //写明fragment的类
    android:name="com.example.day3.fragment.StaticFragment" />

编写fragment的布局文件,运行即可

2. 动态方式

创建新的fragment

创建新的Activity,在布局文件中添加fragment,用于存放加载的fragment

<FrameLayout
    android:id="@+id/dynamic_fragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

在Activity中加载fragment

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//创建的fragment
StaticFragment staticFragment = new StaticFragment();
//绑定位置和相应的fragment
fragmentTransaction.add(R.id.dynamic_fragment, staticFragment);
fragmentTransaction.commit();

六、Fragment的状态恢复及代码实现

1. Activity的状态保存和恢复

当Activity的onSaveInstanceState方法被调用时,Activity会自动收集View Hierachy(视图层次)中每一个View的状态(只有内部实现了View类状态保存和恢复方法的控件才能被收集状态)。回传时,数据与View的对应关系的依据就是id,通常在布局中通过android:id属性定义

这就是输入在 EditText 中的文本内容,在 Activity 已经被销毁且不做任何事情的情况下,依然能够保存的原因,同时这也是为什么那些没有定义 android:id 属性的 View 不能恢复状态的原因

虽然这些 View 的状态可以被自动保存,但是 Activity 成员变量却不行,他们将随着 Activity 一起被销毁。通过 onSaveInstanceStateonRestoreInstanceState 方法手动保存和恢复这些成员变量

public class MainActivity extends AppCompatActivity {

    // These variable are destroyed along with Activity
    private int someVarA;
    private String someVarB;

    ...

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("someVarA", someVarA);
        outState.putString("someVarB", someVarB);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        someVarA = savedInstanceState.getInt("someVarA");
        someVarB = savedInstanceState.getString("someVarB");
    }

}

2. Fragment的状态保存和恢复

与Activity不同的,在恢复Fragment自己的数据时,没有onRestoreInstanceState

public class MainFragment extends Fragment {

    // These variable are destroyed along with Activity
    private int someVarA;
    private String someVarB;

    ...

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt("someVarA", someVarA);
        outState.putString("someVarB", someVarB);
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        someVarA = savedInstanceState.getInt("someVarA");
        someVarB = savedInstanceState.getString("someVarB");
    }

}

一旦 Fragment 从回退栈(BackStack)中返回时,View 将会被销毁和重建,这种情况是,Fragment 没有被销毁,但 Fragment 的 View 被销毁,因此,没有发生 Instance 状态保存。

View 状态保存和恢复在 Fragment 内部被调用,每一个内部实现 View 类保存和恢复方法的 View,例如 EditText 或者 TextView,只要设置了 android:freezeText="true",都将被自动保存和恢复状态。

需要注意的是在这种情况下只有 View 被销毁和重建,Fragment 实例仍然在那儿,包括实例里的成员变量,所以不需要对成员变量做任何事情。

注意:

  • Fragment 状态保存和恢复最佳实践的第一个条件是,项目中用到的每一个 View 内部必须实现状态保存和恢复方法

  • 当使用第三方自定义View或者自己自定义的View时,确保已经实现onSaveInstanceState 和 onRestoreInstanceState 方法

  • 分配 android:id 属性给 Layout 布局中需要支持状态保存和恢复的每一个 View,否则这些 View不会支持恢复状态

  • 不要在 Fragment 的onSaveInstanceState 方法中保存 View 状态,反之亦然

3. 回退栈

类似于Android系统为Activity维护一个任务栈,这里也可以通过Activity维护一个回退栈来保存每次Fragment事务发生变化。如果将Fragment任务添加到回退栈,当用户点击后退按钮时,将看到上一次保存的Fragment。一旦Fragment完全从回退栈中弹出,用户再次点击后退键,则退出当前Activity

方法:FragmentTransaction.addToBackStack(String)

以下使用案例进行介绍

视频中,演示了三个fragment,第一个fragment跳转到第二个fragment,第二个再跳转到第三个,其中我们发现返回时,第一个fragment之前填入的信息没有了,第二个fragment还保留着原来的信息,这就是利用了回退栈。

步骤一:创建三个fragment,下面只展示一个,第二个fragment与第一个类似,第三个没有操作

public class OneFragment extends Fragment implements View.OnClickListener {

    private Button button;
    private EditText editText;

    public interface FOneBtnClickListener{
        void onFOneBtnClick();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_one, container, false);
        button = view.findViewById(R.id.btn_one);
        button.setOnClickListener(this);
        editText = view.findViewById(R.id.et_one);
        return view;
    }

    @Override
    public void onClick(View v) {
        if (getActivity() instanceof FOneBtnClickListener){
            ((FOneBtnClickListener) getActivity()).onFOneBtnClick();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        editText.setText("");
    }
}

步骤二:创建Activity

public class FallBackStackActivity extends AppCompatActivity implements OneFragment.FOneBtnClickListener, TwoFragment.FTwoBtnClickListener {

    private OneFragment oneFragment;
    private TwoFragment twoFragment;
    private ThreeFragment threeFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_fall_back_stack);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        //初始界面的加载
        oneFragment = new OneFragment();
        FragmentManager fManager = getSupportFragmentManager();
        FragmentTransaction fTransaction = fManager.beginTransaction();
        fTransaction.add(R.id.fallback_fragment, oneFragment, "oneFragment");
        fTransaction.commit();
    }

    @Override
    public void onFOneBtnClick(){
        if (twoFragment == null){
            twoFragment = new TwoFragment();
            twoFragment.setFTwoBtnClickListener(this);
        }
        FragmentManager fManager = getSupportFragmentManager();
        FragmentTransaction fTransaction = fManager.beginTransaction();
        //之前在oneFragment中的操作不存在了
        //replace相当于remove+add
        fTransaction.replace(R.id.fallback_fragment, twoFragment, "twoFragment");
        //压入回退栈,返回还能回到oneFragment
        fTransaction.addToBackStack(null);
        fTransaction.commit();
    }

    @Override
    public void onFTwoBtnClick() {
        if (threeFragment == null){
            threeFragment = new ThreeFragment();
        }
        FragmentManager fManager = getSupportFragmentManager();
        FragmentTransaction fTransaction = fManager.beginTransaction();
        //先隐藏,再添加,返回的话,之前在twoFragment的操作还在
        fTransaction.hide(twoFragment);
        fTransaction.add(R.id.fallback_fragment, threeFragment, "threeFragment");
        fTransaction.addToBackStack(null);
        fTransaction.commit();
    }
}

**注意:**使用.addToBackStack(null)压入栈后,fragment的状态就会被记录,如果不希望记录,可以在onStart()onResume()中清除内容。

七、参数传递

1. 同一个Activity,同一个container间参数传递

常见的情况是,Fragment跳转时传递参数,以下举例FirstFragment给SecondFragment传递参数

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_first, container, false);
    Button button = view.findViewById(R.id.btn_first);
    button.setOnClickListener(v -> {

        FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        SecondFragment secondFragment = SecondFragment.newInstance("从FirstFragment传来的参数呀~");
        fragmentTransaction.add(R.id.dynamic_first_fragment, secondFragment);
        fragmentTransaction.hide(FirstFragment.this);
        //按返回键可以回到上一个页面,而不是直接退出
        fragmentTransaction.addToBackStack(null);
        fragmentTransaction.commit();
    });

    return view;
}

在SecondFragment中写一个参数传递函数

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    View view =  inflater.inflate(R.layout.fragment_second, container, false);
    if (getArguments() != null) {
        //提取参数,进行填充
        String mParam1 = getArguments().getString("param");
        TextView tv =  view.findViewById(R.id.tv_second);
        tv.setText(mParam1);
    }
    return view;
}

public static SecondFragment newInstance(String text) {
    SecondFragment fragment = new SecondFragment();
    Bundle args = new Bundle();
    args.putString("param", text);
    fragment.setArguments(args);
    return fragment;
}

2. 同一个Activity,不同的container间的参数传递

在主页面共包含两个fragment,左侧fragment的布局文件为一个textView,一个为listView,右侧fragment布局文件为一个textView。当在左侧点击listView里面的item时,将其显示在右侧,实验效果展示如下:

public class LeftFragment extends Fragment implements AdapterView.OnItemClickListener {

    private titleSelectInterface selectInterface;
    private ListView listView;
    //列表信息
    private String[] mStrings = {"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler", "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
            "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale", "Aisy Cendre",
            "Allgauer Emmentaler"};
    private ArrayAdapter<String> adapter;

    //绑定activity
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        try {
            selectInterface = (titleSelectInterface) context;
        } catch (Exception e) {
            throw new ClassCastException(context + "must implement OnArticleSelectedListener");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View view = inflater.inflate(R.layout.fragment_left, container, false);
        listView = view.findViewById(R.id.list);
        adapter = new ArrayAdapter<>(getActivity(), android.R.layout.simple_list_item_1, mStrings);
        listView.setAdapter(adapter);
        listView.setOnItemClickListener(this);
        return view;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        String str = mStrings[position];
        selectInterface.onTitleSelect(str);
    }

    public interface titleSelectInterface {
        void onTitleSelect(String title);
    }

}
public class PassParameterDifferActivity extends AppCompatActivity implements LeftFragment.titleSelectInterface {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_pass_parameter_differ);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
    }
    
    @Override
    public void onTitleSelect(String title) {
        FragmentManager manager = getSupportFragmentManager();
        RightFragment rightFragment = (RightFragment) manager.findFragmentById(R.id.right_fragment);
        TextView tv_right = rightFragment.getView().findViewById(R.id.tv_right);
        tv_right.setText(title);
    }
}

八、ViewPager+TabLayout+Fragment简单使用

1. ViewPager简介

1.1 介绍总结

  • 继承自ViewGroup,包含多个View,负责翻页

  • 类似于ListView,有自己的适配器,里面用来填充数据页面

  • 一般和Fragment一起使用,更方便的管理页面中Fragement的生命周期,最常用的实现一般有FragmentPagerAdapter和FragmentStatePagerAdapter

1.2 简单使用

  • 步骤一:在布局文件中声明
<androidx.viewpager.widget.ViewPager
    android:id="@+id/view_pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
  • 步骤二:在Activity文件中获取

  • 步骤三:自定义Adapter,配置Adapter

public class MainActivity extends AppCompatActivity {
    private ViewPager mViewPager;//对应的viewPager
    private List<Fragment> mFragments;//view数组

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        OneFragment oneFragment = new OneFragment();
        TwoFragment twoFragment = new TwoFragment();
        ThreeFragment threeFragment = new ThreeFragment();
        mFragments = new ArrayList<>();
        mFragments.add(oneFragment);
        mFragments.add(twoFragment);
        mFragments.add(threeFragment);

        //步骤二
        mViewPager = (ViewPager) findViewById(R.id.viewPager);
        //步骤三
        mViewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
            @Override
            public Fragment getItem(int position) {
                return mFragments.get(position);
            }

            @Override
            public int getCount() {
                return mFragments.size();
            }
        });
    }
}

2. TabLayout

2.1 简介

属于容器控件,提供水平显示Tab的效果,常常和ViewPager配合使用

2.2 属性简介

android.support.design:tabBackground — 设置的背景。 
android.support.design:tabContentStart — 相对起始位置tab的Y轴偏移量。 
android.support.design:tabGravity — tab的布局方式,两个值GRAVITY_CENTER (内容中心显示) 和 GRAVITY_FILL (内容尽可能充满TabLayout)。 
android.support.design:tabIndicatorColor — 设置tab指示器(tab的下划线)的颜色。 
android.support.design:tabIndicatorHeight — 设置tab指示器(tab的下划线)的高度。 
android.support.design:tabMaxWidth — 设置tab选项卡的最大宽度。 
android.support.design:tabMinWidth — 设置tab选项卡的最小宽度。 
android.support.design:tabMode — 设置布局中tab选项卡的行为模式,两个常量MODE_FIXED (固定的tab)和 MODE_SCROLLABLE(滑动的tab)。 
android.support.design:tabPadding — 设置tab的内边距(上下左右)。 
android.support.design:tabPaddingBottom — 设置tab的底部内边距。 
android.support.design:tabPaddingEnd — 设置tab的右侧内边距。 
android.support.design:tabPaddingStart — 设置tab的左侧内边距。 
android.support.design:tabPaddingTop — 设置tab的上方内边距。 
android.support.design:tabSelectedTextColor — 设置tab被选中时的文本颜色。 
android.support.design:tabTextColor — 设置tab默认的文本颜色。 
android.support.design:tabTextAppearance — 设置tab的TextAppearance样式的引用,可以引用另一个资

2.3 使用

  • 引入依赖
implementation("com.google.android.material:material:1.5.0")
  • 在布局文件中声明
<com.google.android.material.tabs.TabLayout
    android:id="@+id/tab_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />        
  • 在Activity中添加
public class MainActivity extends AppCompatActivity{
   

    TabLayout mTabLayout;
 
    @Override
    protected void onCreate(Bundle savedInstanceState){
   
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mTabLayout.addTab(mTabLayout.newTab().setText("首页"));
        mTabLayout.addTab(mTabLayout.newTab().setText("分类"));
        mTabLayout.addTab(mTabLayout.newTab().setText("设置"));
    }

3. 实践案例(ViewPager+TabLayout+Fragment)

步骤一:引入TabLayout的依赖

implementation("com.google.android.material:material:1.5.0")

步骤二:编写Activity的布局文件

<androidx.viewpager.widget.ViewPager
        android:id="@+id/view_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tab_layout"
        app:layout_constraintVertical_bias="0.666" />

<com.google.android.material.tabs.TabLayout
        android:id="@+id/tab_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:tabMode="fixed"
        app:tabGravity="fill" />

步骤三:新建Fragment文件,编写布局文件,布局文件中只有一个TextView

public class TabFragment extends Fragment {
    public TabFragment(String str){
        Bundle b = new Bundle();
        b.putString("key", str);
        setArguments(b);
    }
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_tab, container, false);
        TextView tv_tab = view.findViewById(R.id.tv_tab);
        tv_tab.setText(getArguments().getString("key"));
        tv_tab.setBackgroundColor(Color.rgb((int) (Math.random() * 255), (int) (Math.random() * 255), (int) (Math.random() * 255)));
        return view;
    }
}

步骤四:自定义Adapter


    private List<Fragment> fragmentList;
    private String[] strings;

    public MyPagerAdapter(@NonNull FragmentManager fm, List<Fragment> fragmentList, String[] strings) {
        super(fm);
        this.fragmentList = fragmentList;
        this.strings = strings;
    }

    @NonNull
    @Override
    public Fragment getItem(int position) {
        return fragmentList.get(position);
    }

    //返回显示有多少页面
    @Override
    public int getCount() {
        return fragmentList.size();
    }

    //这个一定要重写,否则不显示标签
    @Nullable
    @Override
    public CharSequence getPageTitle(int position) {

        return strings.length != 0 && position < strings.length ? strings[position] : null;
    }
}

步骤五:ViewPager关联Adapter,TabLayout关联ViewPager

public class ViewTabActivity extends AppCompatActivity {

    private ArrayList<Fragment> fragments = new ArrayList<>();
    private String[] titles = new String[]{"首页", "购物", "个人中心"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EdgeToEdge.enable(this);
        setContentView(R.layout.activity_view_tab);
        ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
            Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
            v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
            return insets;
        });
        init();
    }

    private void init(){
        TabLayout tabLayout = findViewById(R.id.tab_layout);
        ViewPager viewPager = findViewById(R.id.view_pager);
        //创建Fragment,添加到列表中
        for (int i = 0; i < titles.length; i++){
            fragments.add(new TabFragment(titles[i]));
        }

        MyPagerAdapter myPagerAdapter = new MyPagerAdapter(getSupportFragmentManager(), fragments, titles);
        viewPager.setAdapter(myPagerAdapter);
        tabLayout.setupWithViewPager(viewPager);
    }
}