利用TabLayout+Fragment+ViewPager实现标题栏和内容的联动效果是一种比较简单的小功能,现在就让我来带大家看一下如何实现以上功能吧!
一.TabLayout+Fragment+ViewPager+FragmentPagerAdapter:
1.Fragment的布局文件:
这里的布局只是简单地写了一个TextView,如果大家需要实现其它样式的布局,可以自己进行设计编码。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="这是一个Fragment"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
2.Fragment类文件:
package com.example.myapplication.fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;
import com.example.myapplication.R;
public class FirstFragment extends Fragment {
private View mRootView;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mRootView = inflater.inflate(R.layout.fragment_first, container, false);
return mRootView;
}
}
3.Activity的布局文件:
在Activity布局文件中分别引入TabLayout和ViewPager,其中TabLaout需要引入以下TabLayout的依赖包,虽然我发现我本地环境没有添加这个依赖包也是可以的。
//添加TabLayout依赖包
implementation 'com.google.android.material:material:1.0.0'
布局编码如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="40dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager.widget.ViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/tab_layout"
app:layout_constraintTop_toBottomOf="@id/tab_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>
4.Activity的类文件:
Activity的类文件如下所示,在这里,三个页面的Fragment都使用的用一个类文件和布局文件,具体的开发中需要自己按照需求分别添加不同的Fragmet类文件以及对应的布局文件。这里面使用的适配器是FragmentPagerAdapter,目前这种方法处于不推荐使用的状态。
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import com.example.myapplication.fragment.FirstFragment;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = findViewById(R.id.tab_layout);
mViewPager = findViewById(R.id.viewpager);
initData();
}
private void initData() {
//创建数组链表
ArrayList<Fragment> mFragmentList = new ArrayList<>();
ArrayList<String> mTitle = new ArrayList<>();
//向Fragment数组链表中添加Fragment数据
mFragmentList.add(new FirstFragment());
mFragmentList.add(new FirstFragment());
mFragmentList.add(new FirstFragment());
//向Title数组链表中添加字符串数据
mTitle.add("标题1");
mTitle.add("标题2");
mTitle.add("标题3");
//初始化适配器
FragmentPagerAdapter adapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
//获取页面的数量
@Override
public int getCount() {
return mFragmentList.size();
}
//返回指定页面的Fragment
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
//返回指定页面的标题
@Override
public CharSequence getPageTitle(int position) {
return mTitle.get(position);
}
};
//为ViewPager
mViewPager.setAdapter(adapter);
//将ViewPager和TabLayout关联绑定起来
mTabLayout.setupWithViewPager(mViewPager);
}
}
二.TabLayout+Fragment+ViewPager+FragmentStatePagerAdapter:
其它的代码和上面都是一样的,这里面就只贴出不一样的Activity的类文件,其实这里面也是百分之九十五的一样。同样这里面使用的适配器FragmentStatePagerAdapter也处于不推荐使用的状态。
1.Activity的类文件:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import com.example.myapplication.fragment.FirstFragment;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = findViewById(R.id.tab_layout);
mViewPager = findViewById(R.id.viewpager);
initData();
}
private void initData() {
//创建数组链表
ArrayList<Fragment> mFragmentList = new ArrayList<>();
ArrayList<String> mTitle = new ArrayList<>();
//向Fragment数组链表中添加Fragment数据
mFragmentList.add(new FirstFragment());
mFragmentList.add(new FirstFragment());
mFragmentList.add(new FirstFragment());
//向Title数组链表中添加字符串数据
mTitle.add("标题1");
mTitle.add("标题2");
mTitle.add("标题3");
//初始化适配器
FragmentStatePagerAdapter adapter = new FragmentStatePagerAdapter(getSupportFragmentManager()) {
//获取页面的数量
@Override
public int getCount() {
return mFragmentList.size();
}
//返回指定页面的Fragment
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
//返回指定页面的标题
@Override
public CharSequence getPageTitle(int position) {
return mTitle.get(position);
}
};
//为ViewPager
mViewPager.setAdapter(adapter);
//将ViewPager和TabLayout关联绑定起来
mTabLayout.setupWithViewPager(mViewPager);
}
}
三.TabLayout+Fragment+ViewPager2+FragmentStateAdapter:
复用的代码这里就不一一列举了,以下描述不一样的部分。
1.依赖包的导入:
虽然我的本地环境发现没有引入ViewPager2依赖包也是可以引入ViewPager2的,但是这里也给大家列举出来了。
//添加ViewPager2依赖包
implementation 'androidx.viewpager2:viewpager2:1.0.0'
2.Acticity的布局文件:
下面代码和前面的代码几乎是一样的,只是将引入ViewPager改成了引入ViewPager2。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="40dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewpager2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/tab_layout"
app:layout_constraintTop_toBottomOf="@id/tab_layout" />
</androidx.constraintlayout.widget.ConstraintLayout>
3.Activity的类文件:
package com.example.myapplication;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.Lifecycle;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import com.example.myapplication.fragment.FirstFragment;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private TabLayout mTabLayout;
private ViewPager2 mViewPager2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTabLayout = findViewById(R.id.tab_layout);
mViewPager2 = findViewById(R.id.viewpager2);
initData();
}
private void initData() {
//创建数组链表
ArrayList<Fragment> mFragmentList = new ArrayList<>();
ArrayList<String> mTitle = new ArrayList<>();
//向Fragment数组链表中添加Fragment数据
mFragmentList.add(new FirstFragment());
mFragmentList.add(new FirstFragment());
mFragmentList.add(new FirstFragment());
//向Title数组链表中添加字符串数据
mTitle.add("标题1");
mTitle.add("标题2");
mTitle.add("标题3");
//实例化适配器
MyAdapter myAdapter=new MyAdapter(getSupportFragmentManager(),getLifecycle(),mFragmentList);
//设置适配器
mViewPager2.setAdapter(myAdapter);
//TabLayout和Viewpager2进行关联
new TabLayoutMediator(mTabLayout, mViewPager2, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(TabLayout.Tab tab, int position) {
tab.setText(mTitle.get(position));
}
}).attach();
//适配器内部类
public class MyAdapter extends FragmentStateAdapter {
List<Fragment> mFragmentList;
public MyAdapter(FragmentManager fragmentManager,Lifecycle lifecycle, List<Fragment> fragments) {
super(fragmentManager, lifecycle);
mFragmentList = fragments;
}
//返回特定页面的Fragment
@Override
public Fragment createFragment(int position) {
return mFragmentList.get(position);
}
//获取页面的数量
@Override
public int getItemCount() {
return mFragmentList.size();
}
}
}
最后实现的效果可以点击标题进行页面的切换,可以在Fragment所绘制的区域滑动进行页面的切换,但是无法在其它的空白区域滑动进行页面的切换。
上面我们看的不是很清楚在哪块区域可以滑动,为此我们在Activity的布局文件将ViewPager2的背景设置为黑色,即添加如下:
android:background="@color/black"
最后程序运行的效果如下,其中黑色的区域就是可以滑动的区域,其它的区域是不可滑动的。
后来我发现问题出在Activity的布局文件中,对于ViewPager2的高度的设置为wrap_content,就会出现以上的问题,只需要设置为match_parent,即可在所有的区域都能实现滑动的效果。但是这个时候点击标题的时候就不会出现页面滑动的效果,因为这个时候整个区域都是Fragment的一部分。
这时候大家可能会想为什么上面使用ViewPager的时候就不会出现上述的问题,那就让我们一起探索一下吧!我们将Activity的布局文件中的ViewPager的高度设置为wrap_content,并且背景设置为黑色,结果出现的布局如下:
这可能就是ViewPager和ViewPager2的区别吧,这里面的Fragment绘制区域是除了标题栏的剩下所有区域,而不是ViewPager2的一小部分区域。去掉黑色背景,最后程序运行的结果如下:
这里既可以实现点击标题切换页面,也可以实现在标题之外的其它区域 滑动进行页面的切换。
设置为match_parent的时候结果类似,这里就不做描述了,只是点击标题没有页面切换的效果罢了。