目录
一、activity_main.xml布局
二、给ViewPager2 创建适配器
三、ViewPager2 数据源
四、MainActivity.java类
1、初始化数据源。
2、ViewPager2 页面改变监听
这里简单演示实现效果,实现快速开发,并没有太好的UI界面。当掌握好了知识点,再来优化界面。实现上面的效果主要用到 ViewPager2 + Fragment + BottomNavigationView
一、activity_main.xml布局
这里只有两个控件。第一个 ViewPager2,用来放 Fragment。第二个是 BottomNavigationView 实现底部导航。
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/main_viewPager"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="0dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="19dp"
app:layout_constraintBottom_toTopOf="@+id/main_bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/main_bottomNavigationView"
android:layout_width="0dp"
android:layout_height="78dp"
android:layout_marginStart="8dp"
android:layout_marginLeft="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginBottom="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/main_viewPager"
app:menu="@menu/bottomnavigationitem"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
给底部导航增加菜单按钮。在 BottomNavigationView 里添加属性 app:menu="@menu/bottomnavigationitem"。在 res 目录下 New --> Directory 新建一个menu目录。在menu目录上 New --> Menu Source File 新建一个 bottomnavigationitem.xml 文件。
在bottomnavigationitem.xml 里添加一个 item 就是在 底部导航栏里添加了一个可点击的 tab 按钮。注意,item 里面的 icon 属性你可以自己找一下好看的icon,这里简单用 mipmap 里的 ic_launcher.webp 来作为 icon。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/fragment_1"
android:icon="@mipmap/ic_launcher"
android:title="T1"/>
<item
android:id="@+id/fragment_2"
android:icon="@mipmap/ic_launcher"
android:title="T2"/>
<item
android:id="@+id/fragment_3"
android:icon="@mipmap/ic_launcher"
android:title="T3"/>
<item
android:id="@+id/fragment_4"
android:icon="@mipmap/ic_launcher"
android:title="T4"/>
<item
android:id="@+id/fragment_5"
android:icon="@mipmap/ic_launcher"
android:title="T5"/>
</menu>
二、给ViewPager2 创建适配器
ViewPager2 是高级 UI。通过适配器 Adapter 来适配数据源。创建一个 MyFragmentStateAdapter.class 类,继承 FragmentStateAdapter,实现两个方法 createFragment() 和 getItemCount()。
注意:
1、ViewPager 是与 FragmentPagerAdapter 搭配的。而 FragmentPagerAdapter 继承自 PagerAdapter。而 FragmentPagerAdapter 已经被官方给废弃了。
2、ViewPager2 是与 FragmentStateAdapter 搭配的。而 FragmentStateAdapter 继承自 RecyclerView.Adapter。因此可以用到 RecyclerView 的性质,比如垂直滑动效果。
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import java.util.List;
public class MyFragmentStateAdapter extends FragmentStateAdapter {
private List<Fragment> mData;
public MyFragmentStateAdapter(FragmentActivity fragmentActivity, List<Fragment> mData) {
super(fragmentActivity);
this.mData = mData;
}
@NonNull
@Override
public Fragment createFragment(int position) {
return mData.get(position);
}
@Override
public int getItemCount() {
return mData == null ? 0 : mData.size();
}
}
三、ViewPager2 数据源
创建一个 Fragment 来作为 ViewPager2 的数据源。
public class MyFragment extends Fragment{
/**
* 的到当前Fragment 的一个实例
*/
public static MyFragment newInstance(int position){
Bundle bundle = new Bundle();
bundle.putInt("Position", position);
MyFragment fragment = new MyFragment();
fragment.setArguments(bundle);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, tabIndex + "fragment" + "onCreate");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
四、MainActivity.java类
1、初始化数据源。
/**
* 初始化数据
*/
private List<Fragment> initData(){
mData = new ArrayList<>();
for (int i = 0; i < 5; i++) {
mData.add(MyFragment.newInstance(i));
}
return mData;
}
2、ViewPager2 页面改变监听
ViewPager2 里对页面改变的监听是 OnPageChangeCallback(); ViewPager 是 OnPageChangeListener(), 但是已经被废弃了。
BottomNavigationView.setSelectedItemId(itemID) 根据itemID 设置选中的 item。当滑动 Fragment 时,BottomNavigationView 的每个 item 也会相应的改变。做到每个Fragment 与 下面BottomNavigationView 的每个 item 绑定。
ViewPager2.OnPageChangeCallback onPageChangeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
int itemID = R.id.fragment_1;
switch (position) {
case 0:
itemID = R.id.fragment_1;
break;
case 1:
itemID = R.id.fragment_2;
break;
case 2:
itemID = R.id.fragment_3;
break;
case 3:
itemID = R.id.fragment_4;
break;
case 4:
itemID = R.id.fragment_5;
break;
default:
break;
}
//TODO 当Fragment滑动改变时,底部的Tab也跟着改变
mBottomNavigationView.setSelectedItemId(itemID);
}
};
3、BottomNavigationView 的每个 item 点击的监听
对于底部导航栏 item 的监听应该是 OnNavigationItemSelectedListener,但是该方法已经被 google 官方给废弃了,所以这里用 OnItemSelectedListener 来代替。
ViewPager.setCurrentItem() 方法,设置当前 Viewpager 要加载的item (Fragment),这里做到 ViewPager2 的每一个 Fragment 与 底部导航栏的每个 item 绑定。
NavigationBarView.OnItemSelectedListener onItemSelectedListener = new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// 点击Tab, 切换对应的 Fragment
switch (item.getItemId()) {
case R.id.fragment_1:
//TODO 当点击 Tab 时,ViewPager 也切换到对应的 Fragment
mViewPager.setCurrentItem(0, true);
return true;
case R.id.fragment_2:
mViewPager.setCurrentItem(1, true);
return true;
case R.id.fragment_3:
mViewPager.setCurrentItem(2, true);
return true;
case R.id.fragment_4:
mViewPager.setCurrentItem(3, true);
return true;
case R.id.fragment_5:
mViewPager.setCurrentItem(4, true);
return true;
}
return false;
}
};
MainActivity的完整代码
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.Fragment;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import com.example.viewpager2_demo.adapter.MyFragmentStateAdapter;
import com.example.viewpager2_demo.fragment.MyFragment;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;
import java.util.ArrayList;
import java.util.List;
@RequiresApi(api = Build.VERSION_CODES.M)
public class MainActivity extends AppCompatActivity {
private ViewPager2 mViewPager;
private BottomNavigationView mBottomNavigationView;
private List<Fragment> mData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mViewPager = findViewById(R.id.main_viewPager);
mBottomNavigationView = findViewById(R.id.main_bottomNavigationView);
// 设置适配器
mViewPager.setAdapter(new MyFragmentStateAdapter(this, initData()));
mViewPager.setOffscreenPageLimit(1); //设置页面缓存的个数,默认1个
//设置底部导航栏 item 点击的监听
mBottomNavigationView.setOnItemSelectedListener(onItemSelectedListener);
// 设置 ViewPager2 页面改变的监听
mViewPager.registerOnPageChangeCallback(onPageChangeCallback);
}
ViewPager2.OnPageChangeCallback onPageChangeCallback = new ViewPager2.OnPageChangeCallback() {
@Override
public void onPageSelected(int position) {
super.onPageSelected(position);
int itemID = R.id.fragment_1;
switch (position) {
case 0:
itemID = R.id.fragment_1;
Log.d("HL", "1");
break;
case 1:
itemID = R.id.fragment_2;
Log.d("HL", "2");
break;
case 2:
itemID = R.id.fragment_3;
Log.d("HL", "3");
break;
case 3:
itemID = R.id.fragment_4;
Log.d("HL", "4");
break;
case 4:
itemID = R.id.fragment_5;
Log.d("HL", "5");
break;
default:
break;
}
//TODO 当Fragment滑动改变时,底部的Tab也跟着改变
mBottomNavigationView.setSelectedItemId(itemID);
}
};
NavigationBarView.OnItemSelectedListener onItemSelectedListener = new NavigationBarView.OnItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
// 点击Tab, 切换对应的 Fragment
switch (item.getItemId()) {
case R.id.fragment_1:
//TODO 当点击 Tab 时,ViewPager 也切换到对应的 Fragment
mViewPager.setCurrentItem(0, true);
return true;
case R.id.fragment_2:
mViewPager.setCurrentItem(1, true);
return true;
case R.id.fragment_3:
mViewPager.setCurrentItem(2, true);
return true;
case R.id.fragment_4:
mViewPager.setCurrentItem(3, true);
return true;
case R.id.fragment_5:
mViewPager.setCurrentItem(4, true);
return true;
}
return false;
}
};
/**
* 初始化数据
*/
private List<Fragment> initData(){
mData = new ArrayList<>();
for (int i = 0; i < 5; i++) {
mData.add(MyFragment.newInstance(i));
}
return mData;
}
}