Android实现底部导航栏切换并解决Fragment切换时多次加载网络等问题
2019-02-01 19:53
3355 查看
问题描述
问题1 如何实现一个Activity多个Fragment
问题2 底部导航栏fragment切换时会反复加载网络数据,最终造成网络阻塞甚至崩溃
底部导航栏切换时如果使用remove和add方法,这样每次切换都会导致创建多个Fragment实例,所以造成网络阻塞甚至程序崩溃。这里采用hide和show方法来切换fragment
问题3 去掉BottomNavigationMenuView的默认动画效果
为了方便布局采用了BottomNavigationMenuView进行底部导航栏布局,但当底部按钮数量较多时,会有个自带动画效果,这显然不是我们想要的,可以通过反射去掉这个效果。
下面说解决方案
代码实现
编写Fragment,这里创了5个简易的Fragment,代码都是类似的
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import example.com.myapplication.R; public class FiveFragment extends Fragment { public FiveFragment() { // Required empty public constructor } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_five, container, false); } }
对Fragment布局,这里只是简单地加了个背景
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <View android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/md_light_green_A700"/> </LinearLayout>
添加design包,这里版本号根据实际情况自行更改
compile 'com.android.support:design:25.3.1'
activity_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:orientation="vertical" android:layout_height="match_parent"> <FrameLayout android:id="@+id/container" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="vertical"/> <android.support.design.widget.BottomNavigationView android:id="@+id/bottomNav" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="?android:attr/windowBackground" app:itemBackground="@null" app:itemIconTint="@drawable/bottom_navigation_selector" app:itemTextColor="@drawable/bottom_navigation_selector" app:menu="@menu/tab" /> </LinearLayout>
添加tab.xml 用于按钮文字及图片配置
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/navigation_home" android:icon="@drawable/home" android:title="首页" /> <item android:id="@+id/navigation_two" android:icon="@drawable/home" android:title="分类" /> <item android:id="@+id/navigation_three" android:icon="@drawable/home" android:title="圈子" /> <item android:id="@+id/navigation_four" android:icon="@drawable/home" android:title="发现" /> <item android:id="@+id/navigation_five" android:icon="@drawable/home" android:title="记录" /> </menu>
bottom_navigation_selector.xml用于选中和未选中的颜色的配置
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:color="@color/md_red_400" android:state_checked="true" /> <item android:color="@color/md_grey_600" android:state_checked="false" /> </selector>
最后,MainActivity 用isFragment指向当前正在使用的Fragment,同时使用hide和show方法,防止切换时重新创建实例。在去掉底部导航栏动画效果上,采用了反射的方法。
import android.os.Bundle; import android.support.annotation.NonNull; import android.support.design.internal.BottomNavigationItemView; import android.support.design.internal.BottomNavigationMenuView; import android.support.design.widget.BottomNavigationView; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.MenuItem; import java.lang.reflect.Field; import example.com.myapplication.Fragment.FiveFragment; import example.com.myapplication.Fragment.FourFragment; import example.com.myapplication.Fragment.HomeFragment; import example.com.myapplication.Fragment.SecondFragment; import example.com.myapplication.Fragment.ThirdFragment; import static example.com.myapplication.R.id.bottomNav; public class MainActivity extends AppCompatActivity { private BottomNavigationView bottomNavigationView; //定义Fragment private HomeFragment homeFragment; private SecondFragment secondFragment; private ThirdFragment thirdFragment; private FourFragment fourFragment; private FiveFragment fiveFragment; //记录当前正在使用的fragment private Fragment isFragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //初始化Fragment及底部导航栏 initFragment(savedInstanceState); bottomNavigationView = (BottomNavigationView) findViewById(bottomNav); //关闭底部导航栏默认动画效果并添加监听器 disableShiftMode(bottomNavigationView); bottomNavigationView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener); } public void initFragment(Bundle savedInstanceState) { //判断activity是否重建,如果不是,则不需要重新建立fragment. if (savedInstanceState == null) { FragmentManager fm = getSupportFragmentManager(); FragmentTransaction ft = fm.beginTransaction(); if (homeFragment == null) { homeFragment = new HomeFragment(); } isFragment = homeFragment; ft.replace(R.id.container, homeFragment).commit(); } } private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener = new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case R.id.navigation_home: if (homeFragment == null) { homeFragment = new HomeFragment(); } switchContent(isFragment, homeFragment); return true; case R.id.navigation_two: if (secondFragment == null) { secondFragment = new SecondFragment(); } switchContent(isFragment, secondFragment); return true; case R.id.navigation_three: if (thirdFragment == null) { thirdFragment = new ThirdFragment(); } switchContent(isFragment, thirdFragment); return true; case R.id.navigation_four: if (fourFragment == null) { fourFragment = new FourFragment(); } switchContent(isFragment, fourFragment); return true; case R.id.navigation_five: if (fiveFragment == null) { fiveFragment = new FiveFragment(); } switchContent(isFragment, fiveFragment); return true; } return false; } }; public void switchContent(Fragment from, Fragment to) { if (isFragment != to) { isFragment = to; FragmentManager fm = getSupportFragmentManager(); //添加渐隐渐现的动画 FragmentTransaction ft = fm.beginTransaction(); if (!to.isAdded()) { // 先判断是否被add过 ft.hide(from).add(R.id.container, to).commit(); // 隐藏当前的fragment,add下一个到Activity中 } else { ft.hide(from).show(to).commit(); // 隐藏当前的fragment,显示下一个 } } } //利用反射关闭底部导航栏默认动画效果,使多个按钮平分界面 public void disableShiftMode(BottomNavigationView view) { BottomNavigationMenuView menuView = (BottomNavigationMenuView) view.getChildAt(0); try { Field shiftingMode = menuView.getClass().getDeclaredField("mShiftingMode"); shiftingMode.setAccessible(true); shiftingMode.setBoolean(menuView, false); shiftingMode.setAccessible(false); for (int i = 0; i < menuView.getChildCount(); i++) { BottomNavigationItemView item = (BottomNavigationItemView) menuView.getChildAt(i); //noinspection RestrictedApi item.setShiftingMode(false); // set once again checked value, so view will be updated //noinspection RestrictedApi item.setChecked(item.getItemData().isChecked()); } } catch (NoSuchFieldException e) { Log.e("BNVHelper", "Unable to get shift mode field", e); } catch (IllegalAccessException e) { Log.e("BNVHelper", "Unable to change value of shift mode", e); } } }
在本例中,用到了BottomNavigationMenuView作为底部导航栏的布局,实际上不用也可以的,只需要将它替换为线性布局并适当修改代码即可。
整个框架搭建好后,就可以在Fragment中加入网络线程了。
源码下载
相关文章推荐
- 实现底部导航栏及切换tab重新加载的问题解决
- Android项目ViewPager+Fragment+RadioButton实现底部导航栏切换
- 【问题解决】FragmentTabHost 底部菜单栏,切换Frgment时重新加载问题
- Android listview&gridview getview 方法多次调用问题解决方法 并附上单页加载实现问卷调查适配器源代码
- 【Android】解决RadioButton+FragmentPagerAdapter+Fragment切换页面数据加载的问题
- 【转】Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- 解决fragment中嵌套fragment加载切换的问题
- Android 关于fragment切换重新加载的解决分享给大家
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- Android 关于fragment切换重新加载的解决分享给大家
- Android例子—Fragment实例讲解—底部导航栏的实现(方法2)
- Android _关于fragment切换重新加载的解决分享给大家
- Android典型界面设计——FragmentTabHost+Fragment实现底部tab切换
- Android实习札记(5)---Fragment之底部导航栏的实现
- Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信
- 使用LinearLayout+TextView实现底部导航栏,重复切换页面不会重新加载
- Android商城开发系列(三)——使用Fragment+RadioButton实现商城底部导航栏
- 基于android的网络音乐播放器-添加viewpager和fragment实现滑动切换多个界面(二)
- Android解决多个Fragment切换时布局重新实例化问题