android: 结合BottomNavigationView、ViewPager和Fragment 实现左右滑动的效果

主界面:MainActivity

package com.yongdaimi.android.androidapitest;

import android.os.Bundle;

import androidx.appcompat.app.AppCompatActivity;

import com.yongdaimi.android.androidapitest.fragment.HomePageFragment;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initFragment();
    }

    private void initFragment() {
        HomePageFragment homePageFragment = HomePageFragment.newInstance();
        getSupportFragmentManager()
                .beginTransaction()
                .add(R.id.fl_main_container, homePageFragment, homePageFragment.getClass().getSimpleName())
                .commit();
    }

}

主界面布局:activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/fl_main_container"
    />

主界面入口的Fragment: HomePageFragment.java

package com.yongdaimi.android.androidapitest.fragment;

import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager.widget.ViewPager;

import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.bottomnavigation.LabelVisibilityMode;
import com.yongdaimi.android.androidapitest.R;

import java.util.ArrayList;
import java.util.List;

/**
 * A simple {@link Fragment} subclass.
 * Activities that contain this fragment must implement the
 * HomePageFragment.OnFragmentInteractionListener interface
 * to handle interaction events.
 * Use the {@link HomePageFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class HomePageFragment extends Fragment {


    public static final String TAG = "xp.chen";

    private View mContentView;
    private ViewPager vp_pager;
    private BottomNavigationView nv_bottom_menu;

    private List<BaseViewController> mPageList;


    public static HomePageFragment newInstance() {
        return new HomePageFragment();
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        mContentView = inflater.inflate(R.layout.fragment_home_page, container, false);
        return mContentView;
    }


    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initView();
        initPages();
        setListener();
    }


    private void initPages() {
        mPageList = new ArrayList<>();
        HomeViewController homeViewController = new HomeViewController(getActivity());
        mPageList.add(homeViewController);

        ContactViewController contactViewController = new ContactViewController(getActivity());
        mPageList.add(contactViewController);

        SearchViewController searchViewController = new SearchViewController(getActivity());
        mPageList.add(searchViewController);

        SettingsViewController settingsViewController = new SettingsViewController(getActivity());
        mPageList.add(settingsViewController);
        vp_pager.setAdapter(mPagerAdapter);
    }


    private void initView() {
        vp_pager = mContentView.findViewById(R.id.vp_pager);

        nv_bottom_menu = mContentView.findViewById(R.id.nv_bottom_menu);
        nv_bottom_menu.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED);
        nv_bottom_menu.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
    }


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


    private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() {

        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
            vp_pager.setCurrentItem(menuItem.getOrder());
            return true;
        }
    };


    private PagerAdapter mPagerAdapter = new PagerAdapter() {

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

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }

        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {

            BaseViewController baseViewController = mPageList.get(position);
            ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            container.addView(baseViewController, layoutParams);
            return baseViewController;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

        @Override
        public int getItemPosition(Object object) {
            return super.getItemPosition(object);
        }

        @Override
        public void notifyDataSetChanged() {
            super.notifyDataSetChanged();
        }

    };


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

        }

        @Override
        public void onPageSelected(int position) {
            Log.i(TAG, "onPageSelected: " + position);
            nv_bottom_menu.getMenu().getItem(position).setChecked(true);
        }

        @Override
        public void onPageScrollStateChanged(int state) {

        }
    };

}

主界面入口Fragment的布局:fragment_home_page.xml

<?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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <androidx.viewpager.widget.ViewPager
        android:id="@+id/vp_pager"
        android:layout_width="match_parent"
        android:layout_height="0dip"
        android:layout_weight="1"
        />


    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/nv_bottom_menu"
        android:layout_width="match_parent"
        android:layout_height="50dip"
        android:layout_gravity="bottom"
        android:background="?android:attr/windowBackground"
        app:menu="@menu/menu_navigation"
        app:elevation="4dip"
        />

</LinearLayout>

BottomNavigationView的menu文件:menu_navigation.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <item
        android:id="@+id/item_tab1"
        android:icon="@drawable/ic_menu_home"
        android:title="Home"
        android:checked="true"
        android:orderInCategory="0"
        />
    <item
        android:id="@+id/item_tab2"
        android:icon="@drawable/ic_menu_contact"
        android:title="Contact"
        android:orderInCategory="1"
        />
    <item
        android:id="@+id/item_tab3"
        android:icon="@drawable/ic_menu_search"
        android:title="Search"
        android:orderInCategory="2"
        />
    <item
        android:id="@+id/item_tab4"
        android:icon="@drawable/ic_menu_settings"
        android:title="Settings"
        android:orderInCategory="3"
        />

</menu>

这里有几个地方需要特别说明一下:

1.  HomePageFragment.java 文件中的 nv_bottom_menu.setLabelVisibilityMode(LabelVisibilityMode.LABEL_VISIBILITY_LABELED); 用来设置BottomNavigationView在切换时的状态,如果不设置,在点击BottomNavigationView上的item在切换时文字可能会发生隐藏。
2. 上面menu文件中的 orderInCategory 属性用于设置菜单项的排列顺序,必须设置为大于或者等于0的整数值。数值小的排列在前,如果值相等,则按照XML中的顺序展现。 title 属性用于指定navigation Item的标题, icon 属性用于指定navigation item的图标。
3. fragment_home_page文件中的 app:elevation="4dip" 属性用于设置BottomNavigationView菜单顶部的模糊程度,如果不设置的话,BottomNavigationView的菜单顶部会很模糊。

最后是几个用于切换的Layout:

package com.yongdaimi.android.androidapitest.fragment;

import android.content.Context;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;

public abstract class BaseViewController extends FrameLayout {
    
    public BaseViewController(@NonNull Context context) {
        super(context);
    }

}
BaseViewController.java
package com.yongdaimi.android.androidapitest.fragment;

import android.content.Context;
import android.view.LayoutInflater;

import androidx.annotation.NonNull;

import com.yongdaimi.android.androidapitest.R;

public class HomeViewController extends BaseViewController {

    public HomeViewController(@NonNull Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.layout_home, this);
    }

}
HomeViewController.java
package com.yongdaimi.android.androidapitest.fragment;

import android.content.Context;
import android.view.LayoutInflater;

import androidx.annotation.NonNull;

import com.yongdaimi.android.androidapitest.R;

public class ContactViewController extends BaseViewController {

    public ContactViewController(@NonNull Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.layout_contact, this);
    }

}
ContactViewController.java
package com.yongdaimi.android.androidapitest.fragment;

import android.content.Context;
import android.view.LayoutInflater;

import androidx.annotation.NonNull;

import com.yongdaimi.android.androidapitest.R;

public class SearchViewController extends BaseViewController {

    public SearchViewController(@NonNull Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.layout_search, this);
    }

}
SearchViewController.java
package com.yongdaimi.android.androidapitest.fragment;

import android.content.Context;
import android.view.LayoutInflater;

import androidx.annotation.NonNull;

import com.yongdaimi.android.androidapitest.R;

public class SettingsViewController extends BaseViewController {

    public SettingsViewController(@NonNull Context context) {
        super(context);
        LayoutInflater.from(context).inflate(R.layout.layout_settings, this);
    }

}
SettingsViewController.java

基本上都是一样的,它们的布局文件也很简单,就是一个布局里加一个TextView。

最终效果: 

我这里的PageAdapter中并没有直接使用Fragment, 因为ViewPager在加载Fragment时,会同时初始化几个Fragment,这在实际开发中很不友好,目前正在想办法解决,这也是我什么只使用一个Fragment多个Layout的主要原因。如果希望ViewPager中添加的也是Fragment,可参考:

Android布局实现-BottomNavigationView+ViewPager+Fragment+整合

 

posted @ 2019-11-25 18:07  夜行过客  阅读(1178)  评论(0编辑  收藏  举报