前言:
当前大多数应用都是MainActivity + Fragment 通过ViewPager+BottomNavigationView和来实现界面导航。
界面布局:
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
app_bar_main.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"
android:background="@android:color/white">
<com.jiuyin.dianjing.view.CustomViewPager
android:id="@+id/vp_view_container"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav_view"
android:layout_width="match_parent"
android:layout_height="200px"
android:layout_gravity="bottom"
android:layout_marginStart="0dp"
android:layout_marginEnd="0dp"
android:background="?android:attr/windowBackground"
app:itemIconTint="@null"
app:itemTextAppearanceActive="@style/nav_active"
app:itemTextAppearanceInactive="@style/nav_inactive"
app:itemTextColor="@color/color_state_menu_nav"
app:labelVisibilityMode="labeled"
app:menu="@menu/main_bottom_nav_menu"/>
</LinearLayout>
MainActivity.java
@BindView(R.id.vp_view_container)
ViewPager mViewPager;
@BindView(R.id.bottom_nav_view)
BottomNavigationView mBottomNavView;
@BindView(R.id.drawer_layout)
DrawerLayout mDrawerLayout;
@BindView(R.id.nav_view)
NavigationView mNavView;
private SectionsPagerAdapter mSectionsPagerAdapter;
private final List<Fragment> listFragment = new ArrayList<>();
private final CusReceiver mCusReceiver = new CusReceiver();
private final OrderReceiver mOrderReceiver = new OrderReceiver();
private final BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.navigation_first:
mViewPager.setCurrentItem(0);
return true;
case R.id.navigation_second:
mViewPager.setCurrentItem(1);
return true;
case R.id.navigation_third:
mViewPager.setCurrentItem(2);
return true;
case R.id.navigation_four:
mViewPager.setCurrentItem(3);
return true;
case R.id.navigation_five:
mViewPager.setCurrentItem(4);
return true;
default:
break;
}
return false;
}
};
@Override
protected int setLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initData() {
registerReceiver();
listFragment.add(new FragmentFirst());
listFragment.add(new FragmentFirst());
listFragment.add(new FragmentThird());
listFragment.add(new FragmentFirst());
listFragment.add(new FragmentFirst());
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(), listFragment);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mBottomNavView.setSelectedItemId(mBottomNavView.getMenu().getItem(position).getItemId());
}
});
mViewPager.setOffscreenPageLimit(listFragment.size() - 1);
mBottomNavView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
}
@Override
protected void initView() {
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, mDrawerLayout, R.string.app_name, R.string.app_name) {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
//可以重新侧滑方法,该方法实现侧滑动画,整个布局移动效果
//获取mDrawerLayout中的第一个子布局,也就是布局中的RelativeLayout
//获取抽屉的view
View mContent = mDrawerLayout.getChildAt(0);
float scale = 1 - slideOffset;
float endScale = 0.8f + scale * 0.2f;
float startScale = 1 - 0.3f * scale;
//设置左边菜单滑动后的占据屏幕大小
drawerView.setScaleX(startScale);
drawerView.setScaleY(startScale);
//设置菜单透明度
drawerView.setAlpha(0.6f + 0.4f * (1 - scale));
//设置内容界面水平和垂直方向偏转量
//在滑动时内容界面的宽度为 屏幕宽度减去菜单界面所占宽度
mContent.setTranslationX(drawerView.getMeasuredWidth() * (1 - scale));
//设置内容界面操作无效(比如有button就会点击无效)
mContent.invalidate();
//设置右边菜单滑动后的占据屏幕大小
mContent.setScaleX(endScale);
mContent.setScaleY(endScale);
}
};
toggle.syncState();
mDrawerLayout.addDrawerListener(toggle);
mNavView.setItemIconTintList(null);
//设置item的点击事件
mNavView.setNavigationItemSelectedListener(item -> {
int id = item.getItemId();
switch (id) {
case R.id.nav_home:
ToastUtil.showShort("nav_home");
break;
case R.id.nav_gallery:
ToastUtil.showShort("nav_gallery");
break;
case R.id.nav_slideshow:
ToastUtil.showShort("nav_slideshow");
break;
case R.id.nav_tools:
ToastUtil.showShort("nav_tools");
break;
default:
break;
}
mDrawerLayout.closeDrawer(GravityCompat.START);
return true;
});
}
/**
* 主页按返回键返回桌面,程序不退出再次点击图标直接进入程序
* 类似支付宝效果
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
moveTaskToBack(true);
} else {
return false;
}
return true;
}
protected void registerReceiver() {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_NEED_LOGIN);
intentFilter.addAction(ACTION_ORDER_UPLOAD);
LocalBroadcastManager.getInstance(getContext()).registerReceiver(mCusReceiver, intentFilter);
IntentFilter orderIntentFilter = new IntentFilter();
orderIntentFilter.addAction(ACTION_ORDER_UPLOAD);
registerReceiver(mOrderReceiver, orderIntentFilter);
}
protected void unRegisterReceiver() {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mCusReceiver);
unregisterReceiver(mOrderReceiver);
}
@Override
protected void onDestroy() {
unRegisterReceiver();
super.onDestroy();
}
/**
* token过期,重新登录
*/
private void reLogin() {
PMUtil.getInstance().finishAllAC();
Context context = HelperApplication.getContext();
Intent intent = new Intent(context, LoginMobileActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
private class CusReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) {
return;
}
LogUtil.log("MainActivity onReceive action " + action);
if (ACTION_NEED_LOGIN.equals(action)) {
}
}
}
通过ViewPager来绑定和切换Fragment.
如果有不需要ViewPager的地方,可以用其他的方式来实现动态切换。
比如项目中要做的搜索页面包括:
SearchActivity.java
SearchResultFragment.java //搜索结果
SearchSuggestFragment.java //搜索默认界面
SearchWordFragment.java //输入匹配界面
搜索这个界面就需要SearchActivity来控制和切换上述的Fragment。
google新出了一个框架,可以通过fragment来控制和切换Fragment
SearchActivity的布局文件如下:
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_host_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:name="androidx.navigation.fragment.NavHostFragment"
app:defaultNavHost="true"
app:navGraph="@navigation/mobile_navigation"/>
其中代理了个navGraph导航控件,fragment写在mobile_navigation这个文件中。
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/mobile_navigation"
app:startDestination="@+id/nav_search_suggest">
<fragment
android:id="@+id/nav_search_suggest"
android:name="com.jiuyin.dianjing.ui.fragment.search.SearchSuggestFragment" />
<fragment
android:id="@+id/nav_search_wold"
android:name="com.jiuyin.dianjing.ui.fragment.search.SearchWordFragment" />
<fragment
android:id="@+id/nav_search_result"
android:name="com.jiuyin.dianjing.ui.fragment.search.SearchResultFragment" />
</navigation>
定义SearchActivity所需要的三个Fragment,app:startDestination="@+id/nav_search_suggest" 这个指定第一个Fragment。
SearchActivity.java主要代码:
mNavController = Navigation.findNavController(this, R.id.nav_host_fragment);
上述代码主要初始化Navigation。
private void switchFragment(int id, Bundle bundle) {
int current = mNavController.getCurrentDestination().getId();
if (id != R.id.nav_search_suggest) {
if (current != id) {
mNavController.popBackStack();
mNavController.navigate(id);
}
} else {
mNavController.popBackStack();
mNavController.navigate(id, bundle);
}
}
通过上述方法切换Fragment,因为切换的时候需要指定id,切换的时候,根据需要指定id,也就是navigation中定义的id。
通过上述切换Fragment会有个问题,就是切换的Fragment会重新创建,如果你需要当前只有一个的话,不需要其他的保持的话,可以通过上述的mNavController.popBackStack();来解决这个问题。