1 初级版
ViewPager通过滑动来切换Fragment,无底部导航栏。
用法:数据List<Fragment>+适配器FragmentPagerAdapter+ViewPager
通过FragmentPagerAdapter连接两者的桥梁,里面需要重写两个方法getItem,getCount。
第一个方法是获取一个Fragment,从数据源获取。
第二个方法是获取数据源的大小,也就是有几页。
1.1 XML布局文件添加ViewPager
在Activity的XML布局文件中添加一个控件——ViewPager。
加入宽高和ID即可。
在Java代码中找控件ViewPager。
1.2 Java代码创建Adapter类
继承自FragmentPagerAdapter类,重写两个方法getItem,getCount。
public class MyFragmentVPAdapter extends FragmentPagerAdapter { private List<Fragment> fragmentList; public MyFragmentVPAdapter(@NonNull FragmentManager fm,List<Fragment> list) { super(fm); this.fragmentList=list; } @NonNull @Override public Fragment getItem(int position) { return fragmentList==null?null:fragmentList.get(position); } @Override public int getCount() { return fragmentList==null?0:fragmentList.size(); } }
1.2.1 重写方法getItem
获取数据源的位置
public Fragment getItem(int position){ return mFragmentList==null?null:mFragmentList.get(position); }
1.2.2 重写方法getCount
获取数据源的个数
public int getCount(){ return mFragmentList==null?0:mFragmentList.size(); }
1.2.3 适配器构造器
需要传入一个FragmentManager对象和数据源。
1.3 创建Fragment
也是只有一个文本TextView,new的时候传入一个参数来更改文本。
1.4 Java主代码
声明数据源List<Fragment>,实例化适配器。
1.4.1 数据源添加数据
实例化Fragment,用newInstance()。并add到List中。
1.4.2实例化适配器
传入两个参数,getSupportFragmentManager()即可获取FragmentManager对象,数据源。
1.4.3给ViewPager添加适配器
setAdapter即可。
1.4.4 给ViewPager添加监听事件
addOnPageChangeListener(),其中可以设置比如让底部导航栏变色。
2 中级版
ViewPager通过滑动来切换Fragment,有普通的底部导航栏,故也可以通过底部导航栏切换fragment。
用法:ViewPager+FragmentPagerAdapter+普通ButtonView
ViewPager用法+FragmentPagerAdapter的用法+ViewPager和底部导航栏的联动
就是要写很多控件,还要找,比较麻烦。
2.1 XML布局文件添加ViewPager
在Activity的XML布局文件中添加一个控件——ViewPager。
加入宽高和ID即可。
在Java代码中找控件ViewPager。
2.2 Java代码创建Adapter类
继承自FragmentPagerAdapter类,重写两个方法getItem,getCount。
2.3 重写FragmentPagerAdapter的两个方法
同上1.2。
2.4 创建Fragment
也是只有一个文本TextView,new的时候传入一个参数来更改文本。
2.5 Java主代码
声明数据源List<Fragment>,实例化适配器。
2.5.1 数据源添加数据
实例化Fragment,用newInstance()。并add到List中。
2.5.2 实例化适配器
传入两个参数,getSupportFragmentManager()即可获取FragmentManager对象,数据源。
2.5.3 给ViewPager添加适配器
setAdapter即可。
2.6 ViewPager和底部导航栏的联动
当切换页面的时候,把底部导航相应的状态给改变一下。通过ViewPager的addOnPageChangeListener的三个回调。
当点击底部导航时,把Fragment的页面给切换一下。通过线性布局的按钮点击事件的回调。
3 高级版
ViewPager通过滑动来切换Fragment,底部导航栏换成了ButtonNavigationView,故也可以通过底部导航栏切换fragment。
就是在中级版的基础上,把普通按钮换成了另外一个控件ButtonNavigationView,这个控件更加方便。
用法:ViewPager+FragmentPagerAdapter+ButtonNavigationView实现底部导航页
ViewPager用法+FragmentPagerAdapter用法+ButtonNavigationView用法+ViewPager切换页面和ButtonNavigationView的联动+Badge用法(新消息提示)。
3.1 ViewPager用法
数据List<>+适配器FragmentPagerAdapter+ViewPager
3.2 FragmentPagerAdapter用法
继承自FragmentPagerAdapter类,重写两个方法getItem,getCount。
同上1.2。
3.3 ButtonNavigationView用法
有两个重要的属性app:menu(声明导航按钮)和app:labelVisibility(导航按钮的显示模式,有4个值可选)
labeled(一直显示文字),unlabeled(不显示文字),selected(选中显示文字),auto(自动:小于三个按钮取labeled;大于三个按钮取selected)。
3.4 ViewPager切换页面和ButtonNavigationView的联动
3.4.1 ViewPager联动ButtonNavigationView
当ViewPager发生变化时,底部按钮要发生变化
mViewPager.addOnPageChangeListener(...) mBottomNavigationView.setSelectedItemId(R.id.menu_xxx)
3.4.2 ButtonNavigationView联动ViewPager
当点击按钮时,ViewPager要发生变化
mBottomNavigationView.setOnItemSelectedListener(...) mViewPager.setCurrentItem(index)
3.4.3 Badge用法(新消息提示)
创建Badge
//新消息加到菜单中哪个icon中,注册 BadgeDrawable badge=mBottomNavigationView.getOrCreateBadge(R.id.menu_xxx);
设置消息数
//默认是4个字符,只能999+ badge.setNumber(949); //代表只能容下3个字符,99+ //若是4,则是999+ badge.setMaxCharacterCount(3);
到达页面移除badge
mBottomNavigationView.removeBadge(R.id.menu_xxx);
开始写代码咯!
3.5
3.6 创建菜单menu
之前的博客有写,直接创建选项菜单即可。可以在icon选取一个selected选择器,有按下和不按的两种图标状态。我这里没有设置选择器,只有一个icon而已。
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/like" android:icon="@drawable/like" android:title="喜欢"/> <item android:id="@+id/local" android:icon="@drawable/local" android:title="定位"/> <item android:id="@+id/report" android:icon="@drawable/report" android:title="举报"/> <item android:id="@+id/share" android:icon="@drawable/share" android:title="分享"/> </menu>
3.7 XML布局文件添加ViewPager和ButtonNavigationView
最基础的是设置宽高和Id,如果没有ButtonNavigationView控件,可能是没有导入依赖"com.google.android.material:material:1.2.1"。
ViewPager额外设置权重weight属性。
ButtonNavigationView额外设置app:menu和app:labelVisibility。
<?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" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.viewpager.widget.ViewPager android:id="@+id/vp" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btm_nav" app:menu="@menu/btm_menu" app:labelVisibilityMode="labeled"/> </LinearLayout>
3.8 Java主代码获取控件
找两个控件即可。
public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private BottomNavigationView mBottomNavigationView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBottomNavigationView = findViewById(R.id.btm_nav); viewPager = findViewById(R.id.vp); } }
3.9 Java代码创建Adapter类
继承自FragmentStatePagerAdapter类,这个类会回收划掉的页面,而前面那个FragmentPagerAdapter不会回收,会在后台占据着内存,使用方面是一样的。
3.10 重写FragmentPagerAdapter的两个方法
重写getItem,getCount。同上1.2。
3.11 适配器构造器
设置一个传入FragmentManager对象和数据源的构造器。
3.12 创建Fragment
3.12.1 XML文件
也是只有一个文本TextView,new的时候传入一个参数来更改文本。
<?xml version="1.0" encoding="utf-8"?> <FrameLayout 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" tools:context=".viewPagerFragment"> <TextView android:id="@+id/tv_1" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:textSize="25dp" android:text="@string/hello_blank_fragment" /> </FrameLayout>
3.12.2 Java文件
通过传入参数来更改文本
public class viewPagerFragment extends Fragment { private static final String ARG_PARAM1 = "param1"; private static final String ARG_PARAM2 = "param2"; private String mParam1; private String mParam2; private TextView textView; public viewPagerFragment() { } public static viewPagerFragment newInstance(String param1, String param2) { viewPagerFragment fragment = new viewPagerFragment(); Bundle args = new Bundle(); args.putString(ARG_PARAM1, param1); args.putString(ARG_PARAM2, param2); fragment.setArguments(args); return fragment; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mParam1 = getArguments().getString(ARG_PARAM1); mParam2 = getArguments().getString(ARG_PARAM2); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_view_pager, container, false); } @Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); textView= view.findViewById(R.id.tv_1); if(TextUtils.isEmpty(mParam1)){ textView.setText(mParam1); } } }
3.13 Java主代码
声明数据源List<Fragment>,实例化适配器。
List<Fragment> list=new ArrayList<>();
3.13.1 数据源添加数据
实例化Fragment,用newInstance()。并add到List中。
private void initData() { viewPagerFragment viewPagerFragmenthome=viewPagerFragment.newInstance("首页",""); viewPagerFragment viewPagerFragmentfind=viewPagerFragment.newInstance("发现",""); viewPagerFragment viewPagerFragmentmine=viewPagerFragment.newInstance("我的",""); list.add(viewPagerFragmenthome); list.add(viewPagerFragmentfind); list.add(viewPagerFragmentmine); }
3.13.2 实例化适配器
传入两个参数,getSupportFragmentManager()即可获取FragmentManager对象,数据源。
myFragmentVPAdapter = new MyFragmentVPAdapter(getSupportFragmentManager(), list);
3.13.3 给ViewPager添加适配器
setAdapter即可。
viewPager.setAdapter(myFragmentVPAdapter);
3.13.4 给ViewPager添加监听事件
addOnPageChangeListener(),其中可以设置比如让底部导航栏变色。
mViewPager.addOnPageChangeListener(...) mBottomNavigationView.setSelectedItemId(R.id.menu_xxx)
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { switch(position){ case 0: mBottomNavigationView.setSelectedItemId(R.id.like); break; case 1: mBottomNavigationView.setSelectedItemId(R.id.local); break; case 2: mBottomNavigationView.setSelectedItemId(R.id.report); break; case 3: mBottomNavigationView.setSelectedItemId(R.id.share); break; } } @Override public void onPageScrollStateChanged(int state) { } });
写在第二个回调onPageSelected(),然后设置某个icon被选中即可,不需要再取消其他icon的选中状态,这个控件选中其中一个,另外的icon就会被取消,这就是ButtonNavigationView的好处。
3.13.5 给ButtonNavigationView添加监听事件
mBottomNavigationView.setOnItemSelectedListener(),可以让ViewPager切换页面。
//旧方法,已经废弃 mBottomNavigationView.setOnItemSelectedListener(...) //设置ViewPager mViewPager.setCurrentItem(index)
//我们这里不用废弃的旧方法,用setOnItemSelectedListener mBottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch(item.getItemId()){ case R.id.like: viewPager.setCurrentItem(0); break; case R.id.local: viewPager.setCurrentItem(1); break; case R.id.report: viewPager.setCurrentItem(2); break; case R.id.share: viewPager.setCurrentItem(3); break; default: break; } return true; } });
3.14 Badge的设置
3.14.1 Badge的添加
BadgeDrawable badgeDrawable=mBottomNavigationView.getOrCreateBadge(R.id.like); badgeDrawable.setNumber(888); badgeDrawable.setMaxCharacterCount(3);
3.14.2 Badge的移除
在ViewPager的页面监听事件中获取信息,如果到达这个页面的话就移除。
mBottomNavigationView.removeBadge(R.id.like);
最后,上Activity的主代码~
package com.example.fragmentviewpager; import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import androidx.viewpager.widget.ViewPager; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import com.google.android.material.badge.BadgeDrawable; import com.google.android.material.bottomnavigation.BottomNavigationView; import com.google.android.material.navigation.NavigationBarView; import java.util.ArrayList; import java.util.List; public class MainActivity extends AppCompatActivity { private ViewPager viewPager; private BottomNavigationView mBottomNavigationView; private MyFragmentVPAdapter myFragmentVPAdapter; List<Fragment> list=new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mBottomNavigationView = findViewById(R.id.btm_nav); viewPager = findViewById(R.id.vp); initData(); myFragmentVPAdapter = new MyFragmentVPAdapter(getSupportFragmentManager(), list); viewPager.setAdapter(myFragmentVPAdapter); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { switch(position){ case 0: mBottomNavigationView.removeBadge(R.id.like); mBottomNavigationView.setSelectedItemId(R.id.like); break; case 1: mBottomNavigationView.setSelectedItemId(R.id.local); break; case 2: mBottomNavigationView.setSelectedItemId(R.id.report); break; case 3: mBottomNavigationView.setSelectedItemId(R.id.share); break; } } @Override public void onPageScrollStateChanged(int state) { } }); mBottomNavigationView.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch(item.getItemId()){ case R.id.like: viewPager.setCurrentItem(0); break; case R.id.local: viewPager.setCurrentItem(1); break; case R.id.report: viewPager.setCurrentItem(2); break; case R.id.share: viewPager.setCurrentItem(3); break; default: break; } return true; } }); BadgeDrawable badgeDrawable=mBottomNavigationView.getOrCreateBadge(R.id.like); badgeDrawable.setNumber(888); badgeDrawable.setMaxCharacterCount(3); } private void initData() { viewPagerFragment viewPagerFragmenthome=viewPagerFragment.newInstance("首页",""); viewPagerFragment viewPagerFragmentfind=viewPagerFragment.newInstance("发现",""); viewPagerFragment viewPagerFragmentmine=viewPagerFragment.newInstance("我的",""); list.add(viewPagerFragmenthome); list.add(viewPagerFragmentfind); list.add(viewPagerFragmentmine); } }