安卓前端研习——结合viewpager的仿微信界面跳转设计

  利用fragment结合BottomNavigationView可以轻松地做出通用的翻页结构,但是想要使用右滑左滑让界面设计更加人性化,这点还是远远不够的。所以与viewPager结合可以实现更加优化以及人性化的界面设计,具体效果如下:

修改布局资源

  基于上次的博客(国内节点github节点)的布局资源文件做出一点点修改便可以实现这次的效果,首先要引入viewpager到build中

    implementation "androidx.viewpager2:viewpager2:1.0.0"

虽然引入的是viewpager2但还是可以使用viewpager(才不是不会用viewpager2),然后要将底部导航栏中的fragment_container从framelayout更改为viewpager,代码如下:

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/fragment_container"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintHeight_percent="0.9281"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintWidth_percent="1"/>

  此外我们还需要在菜单资源文件的控件中加入新的语句

    android:orderInCategory="0"

这对导航的按钮进行了序号规定,方便图标与实际的fragment进行绑定,修改后完整代码如下:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item
        android:id="@+id/home_home"
        android:icon="@drawable/home_nc"
        android:orderInCategory="0"
        android:enabled="true"
        android:title="首页"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/message"
        android:icon="@drawable/message_nc"
        android:orderInCategory="1"
        android:enabled="true"
        android:title="消息"
        app:showAsAction="ifRoom"/>
    <item
        android:id="@+id/my"
        android:icon="@drawable/my_nc"
        android:orderInCategory="2"
        android:enabled="true"
        android:title="我的"
        app:showAsAction="ifRoom"/>
</menu>

  因为viewpager是不支持直接加入子控件的所以我们需要使用java代码为其配置adapter。

创建viewpager的adapter

  之前只利用底部导航栏以及碎片的方式进行页面跳转的原理是将碎片直接添加到framelayout中作为子控件,但是更换为viewpager后不再支持直接添加子控件了,所以要为viewpager绑定一个adapter使它正常工作。代码如下:

    private List<Fragment> pageList;
    private View vpg_container;
    private ViewPager view_pager;
    private BottomNavigationView menu_bar;

    private void initView(){
        view_pager = vpg_container.findViewById(R.id.fragment_container);

        menu_bar = vpg_container.findViewById(R.id.navigation_bar);
        menu_bar.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
        menu_bar.setOnNavigationItemSelectedListener(mNavigationItemSelectedListener);

        assert getFragmentManager() != null;
        view_pager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
            @Override
            @NonNull
            public Fragment getItem(int position) {
                return pageList.get(position);
            }

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

其中initView方法中的view_pager.setAdapter便是为viewpager绑定了一个adapter,public Fragment getItem(int position) 这个函数将从多个fragment的list中取出一个fragment用于显示,也就是绑定到滑动上了,只要做出滑动页面的操作便可以更改fragment,其中pageList是fragment的arraylist,其生成方法为:

    private void initPage(){
        pageList = new ArrayList<>();
        HomeFragment home = new HomeFragment();
        pageList.add(home);

        MessageFragment message = new MessageFragment();
        pageList.add(message);

        MyFragment my = new MyFragment();
        pageList.add(my);
    }

绑定viewpager操作与BottomNavigationView操作

  有一个重要的点就是我们需要将viewpager的滑动绑定到底部导航栏中,实现滑动页面时底部导航栏选中的图标也会跟着一起改变,这里就要运用到界面改变监听器(OnPageChangeListener),代码如下:

    private void setListener(){
        view_pager.addOnPageChangeListener(mOnPageChangeListener);
    }

    private ViewPager.OnPageChangeListener mOnPageChangeListener =
            new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {
                    menu_bar.getMenu().getItem(position).setChecked(true);
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            };

其中的 public void onPageSelected(int position) 就将页面滑动绑定到了底部导航栏中,需要注意的还是选中的图标状态是checked而不是selected所以要使用 setChecked(true) ,同样的我们还需要将底部导航栏绑定到页面切换,不然点击底部导航栏中的图标是不会切换页面的。实现代码如下:

    private BottomNavigationView.OnNavigationItemSelectedListener mNavigationItemSelectedListener =
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                    view_pager.setCurrentItem(menuItem.getOrder());
                    return false;
                }
            };

其中的 menuItem.getOrder() 获取的是菜单资源文件中 android:orderInCategory 的值,所以一定按照顺序将fragment加入到arraylist中。至此便可以实现如博客开头的效果了,这里将全部更改后的代码贴出来。

完整Java资源代码

完整Java代码如下:

public class MainPageFragment extends Fragment {
    private List<Fragment> pageList;
    private View vpg_container;
    private ViewPager view_pager;
    private BottomNavigationView menu_bar;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
        vpg_container = inflater.inflate(R.layout.main_page_layout, container, false);
        return vpg_container;
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        initPage();  //将页面添加进arrayList
        initView();  //初始化viewpager,添加adapter
        setListener();  //设置监听
    }

    private void initPage(){
        pageList = new ArrayList<>();
        HomeFragment home = new HomeFragment();
        pageList.add(home);

        MessageFragment message = new MessageFragment();
        pageList.add(message);

        MyFragment my = new MyFragment();
        pageList.add(my);
    }

    private void initView(){
        view_pager = vpg_container.findViewById(R.id.fragment_container);

        menu_bar = vpg_container.findViewById(R.id.navigation_bar);
        menu_bar.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
        menu_bar.setOnNavigationItemSelectedListener(mNavigationItemSelectedListener);

        assert getFragmentManager() != null;
        view_pager.setAdapter(new FragmentPagerAdapter(getFragmentManager()) {
            @Override
            @NonNull
            public Fragment getItem(int position) {
                return pageList.get(position);
            }

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

    private void setListener(){
        view_pager.addOnPageChangeListener(mOnPageChangeListener);
    }

    private BottomNavigationView.OnNavigationItemSelectedListener mNavigationItemSelectedListener =
            new BottomNavigationView.OnNavigationItemSelectedListener() {
                @Override
                public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
                    view_pager.setCurrentItem(menuItem.getOrder());
                    return false;
                }
            };

    private ViewPager.OnPageChangeListener mOnPageChangeListener =
            new ViewPager.OnPageChangeListener() {
                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {

                }

                @Override
                public void onPageSelected(int position) {
                    menu_bar.getMenu().getItem(position).setChecked(true);
                }

                @Override
                public void onPageScrollStateChanged(int state) {

                }
            };
}

初めて会ったの日から 僕の心の全てを奪った