一、ViewPager2的基本用法
使用前先添加依赖:
implementation 'androidx.appcompat:appcompat:1.4.0' // AndroidX AppCompat
implementation 'com.google.android.material:material:1.4.0' // Material Design Components
1、制作Fragment
首先制作一个Fragment的xml布局页面
<?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:gravity="center"
android:text="SSSSS"
android:textSize="19sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
然后使用Fragment类绑定这个布局
public class HomeFragment extends Fragment {
FragmentBinding binding;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
binding = FragmentBinding.inflate(inflater,container,false);
return binding.getRoot();
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
2、制作Adapter
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
自定义自己的Adapter继承FragmentStateAdapter
制作一个fragmentList管理所有的fragment
public class MyPagerAdapter extends FragmentStateAdapter {
List<Fragment> fragmentList; //管理所有的fragment
public MyPagerAdapter(@NonNull FragmentActivity fragmentActivity, List<Fragment> fragmentList) {
super(fragmentActivity);
this.fragmentList = fragmentList;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return fragmentList.get(position);
}
@Override
public int getItemCount() {
return fragmentList != null ? fragmentList.size() : 0;
}
}
createFragment
:用于返回指定的frgment界面
getItemCount
:用于加载容器大小
除此之外,FragmentStateAdapter有三个构造方法剩下两个分别是:
public FragmentStateAdapter(@NonNull Fragment fragment)
public FragmentStateAdapter(@NonNull FragmentManager fragmentManager,@NonNull Lifecycle lifecycle)
FragmentStateAdapter(Fragment fragment):
这个构造方法通常用于在 Fragment 内部创建 FragmentStateAdapter
,并将其附加到该 Fragment 的生命周期。
public class MyFragment extends Fragment {
private ViewPager2 viewPager;
private FragmentStateAdapter adapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_layout, container, false);
// 初始化 ViewPager2
viewPager = rootView.findViewById(R.id.viewPager);
// 创建适配器并将其附加到当前 Fragment 的生命周期
adapter = new MyFragmentStateAdapter(this);
viewPager.setAdapter(adapter);
return rootView;
}
}
FragmentStateAdapter(FragmentManager fragmentManager, Lifecycle lifecycle)
这个构造方法通常用于在活动中创建 FragmentStateAdapter
,并通过提供 FragmentManager
和 Lifecycle
对象来管理 Fragment 的生命周期。
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager;
private FragmentStateAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 初始化 ViewPager2
viewPager = findViewById(R.id.viewPager);
// 创建适配器并将其附加到活动的生命周期
adapter = new MyFragmentStateAdapter(getSupportFragmentManager(), getLifecycle());
viewPager.setAdapter(adapter);
}
}
3、使用Adapter加载fragment页面
List<Fragment> fragmentList = new ArrayList<>();
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
fragmentList.add(new HomeFragment());
MyPagerAdapter adapter = new MyPagerAdapter(this,fragmentList);
//禁用预加载
binding.viewPager.setOffscreenPageLimit(ViewPager2.OFFSCREEN_PAGE_LIMIT_DEFAULT);
binding.viewPager.setAdapter(adapter);
预加载是在页面还未滑动时,提前加载页面。一般默认加载1个页面。
FragmentStateAdapter内部封装有 FragmentManager
和 FragmentTransaction
,用于管理Fragment;
使用FragmentManager可以根据ID或TAG来查找Fragment , 动态添加、删除、替换
让Fragment 成为ViewPager的一页时,FragmentManager会一直保存管理创建好了的Fragment,即使当前不是显示的这一页,Fragment对象也不会被销毁,在后台默默等待重新显示。但如果Fragment不再可见时,它的视图层次会被销毁掉,下次显示时视图会重新创建
二、ViewPager2和TabLayout协同使用
1、制作TabLayout与ViewPager2布局文件
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tabIndicatorColor="#1E90FF"
app:tabIndicatorAnimationMode="elastic"
app:tabSelectedTextColor="#B22222"
app:tabUnboundedRipple="true"
app:tabGravity="center"
app:tabMode="auto" >
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"/>
<!-- ViewPager2内部通过RecyclerView 所以需要通过orientation来设置页面切换方向-->
</LinearLayout>
**tabIndicatorAnimationMode ** :设置加载动画样式,elastic
表示粘粘性动画,linear
表示线性动画
tabIndicatorColor :指示器颜色
tabIndicatorHeight :指示器高度
tabIndicatorFullWidth :设置为false 则指示器跟文本宽度一致
tabUnboundedRipple :设置为true点击时会有一个水波纹效果
tabGravity :可设置center或fill;center指的是居中显示,fill指的是沾满全屏。
tabMode :可设置fixed和 scrollable;fixed:指的是固定tab;scrollable指的是tab可滑动。
tabTextColor :tab文字颜色
tabSelectedTextColor :选中时的tab颜色
关于更多的TabLayou的使用可以参考:Android控件-TabLayout使用介绍
2、绑定TabLayout到ViewPager2
2.1 动态自定义Tab
这里采取了自定义TabView的方式,同样的也可以直接操作tab修改样式。
new TabLayoutMediator(binding.tabMode, binding.viewPager, new TabLayoutMediator.TabConfigurationStrategy() {
@Override
public void onConfigureTab(@NonNull TabLayout.Tab tab, int position) {
//自定义TabView
TextView tabView = new TextView(MainActivity.this);
tabView.setText("Fragment " + position);
//将tabbView绑定到tab
tab.setCustomView(tabView);
}
}).attach();
注意一定要使用.attach()
进行启动。
2.2 静态自定义Tab——tabTextAppearance
设置文字的大小和样式,在values下新建文件如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="tabDome">
<item name="android:textSize">20sp</item>
<item name="android:textStyle">bold</item>
</style>
</resources>
在TabLayout中导入文件即可
3、Viewpager2的滑动监听事件
ViewPager2.OnPageChangeCallback有三个构造方法:
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
//该方法开始滑动到滑动结束前不断调用
// 参数一:position表示当前页面的位置(当前页面在翻页适配器中的下标,索引),因为不断调用,position也可能表示目标页面的下标
// 参数二:positionOffset表示页面偏移的百分比,翻页时不断增大(不断趋近1),最后翻页完成时突变成0
// 这个参数在左滑时由1趋近0,右滑由0趋近1
// 参数三:positionOffsetPixel表示页面也已的像素数,变化趋势和positionOffset一样
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
super.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
//该方法在页面切换成功后调用(滑动前与滑动后不是同一页面)
//position表示当前页面在适配器中的下标,索引
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
}
//该方法在页面滑动状态改变时调用
// ViewPager.SCROLL_STATE_IDLE表示空闲状态,当前页面处于静止状态,没有要翻页的趋势
// ViewPager.SCROLL_STATE_DRAGGING表示拖动状态,用户正在拖动页面,准备进行翻页滚动
// ViewPager.SCROLL_STATE_SETTLING表示滚动状态,页面正在自动滚动到目标页面
@Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
3.1 使用动态方法实现字体大小颜色变化
监听ViewPager2的页面滑动实现修改tab
//viewPager 页面切换监听
binding.viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
//用于回调ViewPager2的当前页面,当页面发送变化就会调用这个方法onPageSelected
@Override
public void onPageSelected(int position) {
//获取总的TabLayout的个数
int tabCount = binding.tabMode.getTabCount();
//遍历选择所有的Tab,如果判断是当前的Tab则进行相关操作,不是则还原操作
for (int i = 0; i < tabCount; i++) {
TabLayout.Tab tab = binding.tabMode.getTabAt(i); //取得tab
//通过tab获取tabView
TextView tabView = (TextView) tab.getCustomView();
if (tab.getPosition() == position) {
tabView.setTextSize(20);
tabView.setTypeface(Typeface.DEFAULT_BOLD);
tabView.setTextColor(Color.parseColor("#B22222"));
} else {
tabView.setTextSize(15);
tabView.setTypeface(Typeface.MONOSPACE);
tabView.setTextColor(Color.parseColor("#000000"));
}
}
}
});
3.2 使用静态的方法实现字体大小和颜色变化
首先设置静态的style选项卡,在values下新建一个xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TabLayoutTextSelected">
<item name="android:textSize">20sp</item>
<item name="android:textColor">#B22222</item>
</style>
<style name="TabLayoutTextUnSelected">
<item name="android:textSize">15sp</item>
<item name="android:textColor">#000080</item>
</style>
</resources>
然后在TabLayout的布局文件中设置初始状态的tab颜色字体
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabMode"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:tabIndicatorColor="#1E90FF"
app:tabUnboundedRipple="true"
app:tabGravity="center"
app:tabMode="auto"
app:tabTextAppearance="@style/TabLayoutTextUnSelected"> //注意在这个地方使用tabTextAppearance设置初始状态tab的文字效果
</com.google.android.material.tabs.TabLayout>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/viewPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"/>
</LinearLayout>
监听TabLayout实现修改,TabLayout监听事件有三个Override方法,当然这里也可以继续使用ViewPager2页面的监听方法实现。
binding.tabMode.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
//选中时的变化
@Override
public void onTabSelected(TabLayout.Tab tab) {
// 创建新的 TextView 实例,并设置样式和文本
TextView selectedTextView = new TextView(MainActivity.this);
selectedTextView.setTextAppearance(R.style.TabLayoutTextSelected); //在这里动态使用刚刚的style文件
selectedTextView.setText("Fragment " + tab.getPosition()); //设置文字内容,tab因为是重新加载的textView内容,所以原来的数据被覆盖掉了
tab.setCustomView(selectedTextView);
}
//未选中时的变化
@Override
public void onTabUnselected(TabLayout.Tab tab) {
// 清除未选中标签的自定义视图
tab.setCustomView(null);
}
//重复选中的变化,当用户再次点击已经选中的Tab时,这个方法就会被调用。
@Override
public void onTabReselected(TabLayout.Tab tab) {
// 处理标签重新选择,如果需要
}
});
注意点:
1、在onTabSelected
中重新设置加载的文本内容,否则原数据会被覆盖,出现这样的情况
2、在onTabUnselected
中一定要清除覆盖在tab的自定义视图否则视图会不停重复的加在tab上面,出现这样的情况:
4、TabLayout的监听事件
binding.tabMode.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
TextView textView = new TextView(MainActivity.this);
@Override
public void onTabSelected(TabLayout.Tab tab) {
//选中时的变化
}
public void onTabUnselected(TabLayout.Tab tab) {
//未选中的变化
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
//重复选中的变化,当用户再次点击已经选中的Tab时,这个方法就会被调用。
}
});
5、禁止Viewpager2左右滑动翻页
//false表示禁止,true表示允许
binding.viewPager.setUserInputEnabled(false);
此时就只能通过点击Tab才能加载Fragment.
6、TabLayout+Viewpager2效果展示