BottomNavigationView+viewpager动态设置底部导航栏
最近做毕设,要实现底部导航栏随不同角色登录改变,用了一整个下午完成,所以写个笔记供读者阅览。
一.实现过程
1.导包(AS创建项目自带)
implementation 'com.google.android.material:material:1.1.0'
2.xml文件
如果仅实现静态的导航栏,则直接添加app:menu(没有CustomViewPager,可以直接用ViewPager)
<com.ssa.seniorabilityassessment.CustomViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/bottom_navigation" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_marginBottom="1dp" android:layout_alignParentLeft="true" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@color/white" app:itemIconTint="@drawable/bottom_navigation_selector" app:itemTextColor="@drawable/bottom_navigation_selector" />
menu中的内容:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/item_home" android:icon="@drawable/ic_baseline_home_24" android:title="首页" /> <item android:id="@+id/item_lib" android:icon="@drawable/ic_baseline_explore_24" android:title="发现" /> <item android:id="@+id/item_assess" android:icon="@drawable/ic_baseline_location_on_24" android:title="导航" /> <item android:id="@+id/item_person" android:icon="@drawable/ic_baseline_person_24" android:title="我的" /> </menu>
若使用动态的,需要把app:menu去掉,在activity中写。
3.Activity
①动态添加menu
bottomNavigationView.getMenu().add(0, 0, 0, "首页");
bottomNavigationView.getMenu().findItem(0).setIcon(R.drawable.ic_baseline_home_24);
②设置监听BottomNavigationView点击事件
bottomNavigationView.setOnNavigationItemSelectedListener( new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case 0: viewPager.setCurrentItem(0,false); break; case 1: viewPager.setCurrentItem(1,false); break; case 2: viewPager.setCurrentItem(2,false); break; case 3: viewPager.setCurrentItem(3,false); break; } return false; } });
③创建并添加fragment
//fragments列表 List<Fragment> fragmentList = new ArrayList<>(); //将fragment添加进去 fragmentList.add(new PersonFragment());
④ViewPager监听
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (menuItem != null) { menuItem.setChecked(false); } else { bottomNavigationView.getMenu().getItem(0).setChecked(false); } menuItem = bottomNavigationView.getMenu().getItem(position); menuItem.setChecked(true); } @Override public void onPageScrollStateChanged(int state) { } });
⑤适配器(重要)
适配器要使用FragmentStatePagerAdapter不要使用FragmentPagerAdapter,使用FragmentPagerAdapter时,第一次进入各fragment页面都会正常显示,但是当你切换角色时,比如由四个菜单编程两个菜单时,会发现菜单与fragment内容不一致,这是由于第一次会正常调用FragmentPagerAdapter的getItem()的方法,之后返回进入都不会在调用,除非关闭整个最外层的Activity才进入才会正常显示;之所以没有调用是因为FragmentPagerAdapter中有缓存没有移除之前内部已经包含的fragment,所以我选择使用FragmentStatePagerAdapter来替换FragmentPagerAdapter,每次退出都是remove之前的Fragment
ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(),fragmentList); viewPager.setAdapter(adapter);
public class ViewPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> mFragmentList; private FragmentManager fm; public ViewPagerAdapter(FragmentManager manager,List<Fragment> fragmentList) { super(manager); fm = manager; mFragmentList = fragmentList; } @NotNull @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } }
二.遇到的问题
使用FragmentStatePagerAdapter,可能会导致页面变白,没有内容,我第一次使用的时候是按照不同角色在if判断条件中去添加menu,但是这样运行后会导致页面变白,所以需要直接把所有页面先add添加进去,然后那些不需要的menu直接隐藏掉。
三.完整代码
MainActivity
import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; import android.view.View; import android.widget.PopupMenu; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentTransaction; import androidx.viewpager.widget.ViewPager; import androidx.viewpager2.adapter.FragmentStateAdapter; import com.ssa.seniorabilityassessment.fragment.AssessFragment; import com.ssa.seniorabilityassessment.fragment.ChartFragment; import com.ssa.seniorabilityassessment.fragment.HomeFragment; import com.ssa.seniorabilityassessment.fragment.PersonFragment; import com.google.android.material.bottomnavigation.BottomNavigationView; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.List; import static com.ssa.seniorabilityassessment.LoginActivity.LOGIN_OK; public class MainActivity extends FragmentActivity { MenuItem menuItem; private List<Fragment> fragmentList; @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); try { initViewPager(); } catch (JSONException e) { e.printStackTrace(); } } @RequiresApi(api = Build.VERSION_CODES.KITKAT) public void initViewPager() throws JSONException { fragmentList = new ArrayList<>(); BottomNavigationView bottomNavigationView = findViewById(R.id.bottom_navigation);; CustomViewPager viewPager; viewPager = findViewById(R.id.viewpager); viewPager.setPagingEnabled(false); viewPager.setOffscreenPageLimit(4); //默认 >3 的选中效果会影响ViewPager的滑动切换时的效果,故利用反射去掉 //BottomNavigationViewHelper.disableShiftMode(bottomNavigationView); SharedPreferences sp=getSharedPreferences("User",MODE_PRIVATE); if(bottomNavigationView.getMenu().size() != 0){ bottomNavigationView.getMenu().clear(); } //添加菜单 bottomNavigationView.getMenu().add(0, 0, 0, "首页"); bottomNavigationView.getMenu().findItem(0).setIcon(R.drawable.ic_baseline_home_24); bottomNavigationView.getMenu().add(0, 1, 1, "评估"); bottomNavigationView.getMenu().findItem(1).setIcon(R.drawable.ic_baseline_explore_24); bottomNavigationView.getMenu().add(0, 2, 2, "数据中心"); bottomNavigationView.getMenu().getItem(2).setIcon(R.drawable.ic_baseline_location_on_24); bottomNavigationView.getMenu().add(0,3, 3, "我的"); bottomNavigationView.getMenu().getItem(3).setIcon(R.drawable.ic_baseline_person_24); fragmentList.add(new HomeFragment()); if(sp.getString("data",null) != null){ JSONObject jsonObject = new JSONObject(sp.getString("data",null)); //按照不同角色添加fragment,隐藏菜单 if(jsonObject.getString("role").equals("ROLE_USER")){ bottomNavigationView.getMenu().removeItem(1); bottomNavigationView.getMenu().removeItem(2); fragmentList.add(new PersonFragment()); } else if (jsonObject.getString("role").equals("ROLE_ASSESSOR")){ fragmentList.add(new AssessFragment()); fragmentList.add(new ChartFragment()); fragmentList.add(new PersonFragment()); } else if (jsonObject.getString("role").equals("ROLE_ADMIN")){ fragmentList.add(new AssessFragment()); fragmentList.add(new ChartFragment()); fragmentList.add(new PersonFragment()); } else { bottomNavigationView.getMenu().removeItem(1); bottomNavigationView.getMenu().removeItem(2); fragmentList.add(new PersonFragment()); } } else{ bottomNavigationView.getMenu().removeItem(1); bottomNavigationView.getMenu().removeItem(2); fragmentList.add(new PersonFragment()); } /** * 监听BottomNavigationView点击事件 */ bottomNavigationView.setOnNavigationItemSelectedListener( new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { switch (item.getItemId()) { case 0: viewPager.setCurrentItem(0,false); break; case 1: viewPager.setCurrentItem(1,false); break; case 2: viewPager.setCurrentItem(2,false); break; case 3: viewPager.setCurrentItem(3,false); break; } return false; } }); viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } @Override public void onPageSelected(int position) { if (menuItem != null) { menuItem.setChecked(false); } else { bottomNavigationView.getMenu().getItem(0).setChecked(false); } menuItem = bottomNavigationView.getMenu().getItem(position); menuItem.setChecked(true); } @Override public void onPageScrollStateChanged(int state) { } }); System.out.println(fragmentList); ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager(),fragmentList); viewPager.setAdapter(adapter); } @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == LOGIN_OK) { try { initViewPager(); } catch (JSONException e) { e.printStackTrace(); } } } }
ViewPagerAdapter
import android.content.Context; import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentPagerAdapter; import androidx.fragment.app.FragmentStatePagerAdapter; import androidx.fragment.app.FragmentTransaction; import androidx.viewpager2.adapter.FragmentStateAdapter; import org.jetbrains.annotations.NotNull; import java.util.ArrayList; import java.util.List; public class ViewPagerAdapter extends FragmentStatePagerAdapter { private List<Fragment> mFragmentList; private FragmentManager fm; public ViewPagerAdapter(FragmentManager manager,List<Fragment> fragmentList) { super(manager); fm = manager; mFragmentList = fragmentList; } @NotNull @Override public Fragment getItem(int position) { return mFragmentList.get(position); } @Override public int getCount() { return mFragmentList.size(); } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.ssa.seniorabilityassessment.CustomViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/bottom_navigation" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_marginBottom="1dp" android:layout_alignParentLeft="true" /> <com.google.android.material.bottomnavigation.BottomNavigationView android:id="@+id/bottom_navigation" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:background="@color/white" app:itemIconTint="@drawable/bottom_navigation_selector" app:itemTextColor="@drawable/bottom_navigation_selector" /> <View android:layout_width="match_parent" android:layout_height="5dp" android:layout_above="@id/bottom_navigation" android:background="@drawable/bottom_shadow" /> </RelativeLayout>
LoginActivity
package com.ssa.seniorabilityassessment; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; import androidx.appcompat.app.AppCompatActivity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.os.Looper; import android.util.Log; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import com.google.gson.Gson; import com.ssa.seniorabilityassessment.entity.UserDTO; import org.json.JSONException; import org.json.JSONObject; import java.util.Timer; import java.util.TimerTask; import java.util.regex.Pattern; import okhttp3.FormBody; import okhttp3.MediaType; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class LoginActivity extends AppCompatActivity implements View.OnClickListener{ private Button btn_login; private EditText et_account; private EditText et_password; public static final int LOGIN_OK = 3; SharedPreferences sp=null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initUI(); initData(); } public void initUI(){ btn_login = findViewById(R.id.btn_login); et_account = findViewById(R.id.et_account); et_password = findViewById(R.id.et_password); et_account.setFocusable(true); et_account.setFocusableInTouchMode(true); et_account.requestFocus(); Timer timer =new Timer(); timer.schedule(new TimerTask(){ @Override public void run() { InputMethodManager inputManager=(InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.showSoftInput(et_account,0); }}, 200); sp= getSharedPreferences("User",MODE_PRIVATE); } public void initData(){ btn_login.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent=new Intent(); int id=v.getId(); switch (id){ case R.id.btn_back: finish(); break; // case R.id.btn_register: // intent.setClass(LoginActivity.this,RegisterActivity.class); // startActivityForResult(intent,REG); // break; // case R.id.btn_forget: // intent.setClass(LoginActivity.this,ForgetActivity.class); // startActivityForResult(intent,FOG); // break; case R.id.btn_login: String account=et_account.getText().toString().trim(); String password=et_password.getText().toString(); if(account.length()==0){ Toast.makeText(LoginActivity.this,"用户名不能为空",Toast.LENGTH_SHORT).show(); return; } if(password.length()==0){ Toast.makeText(LoginActivity.this,"密码不能为空",Toast.LENGTH_SHORT).show(); return; } new Thread(){ @RequiresApi(api = Build.VERSION_CODES.KITKAT) @Override public void run() { super.run(); Looper.prepare(); try { //调用后端接口,设置参数 JSONObject jsonUser = new JSONObject(); jsonUser.put("username",account); jsonUser.put("password",password); //发送请求,可以使用默认的http,这里使用okhttp请求 OkHttpClient client = new OkHttpClient();//创建client对象 //发送请求 Request request = new Request.Builder() .url("xxxxxxxxxxxxx") .post(RequestBody.Companion.create(jsonUser.toString(), MediaType.Companion.parse("application/json;charset=utf-8"))) .build(); Response response = client.newCall(request).execute();//执行发送的指令,并接收后端接口返回的数据 String responseData = response.body().string();//获取返回过来的json格式结果 JSONObject jsonObject = new JSONObject(responseData); if(jsonObject.getString("code").equals("200")){ //存储手机号和姓名,方便调用 SharedPreferences.Editor edit=sp.edit(); edit.clear(); edit.putString("data",jsonObject.getString("data")); edit.putString("avatar",new JSONObject(jsonObject.getString("data")).getString("avatarUrl")); edit.commit(); //intent.setClass(LoginActivity.this,MainActivity.class); intent.putExtra("data",jsonObject.getString("data")); intent.putExtra("avatar",new JSONObject(jsonObject.getString("data")).getString("avatarUrl")); System.out.println("登录"+jsonObject.getString("data")); //startActivity(intent); setResult(LOGIN_OK, intent); finish(); runOnUiThread(new Runnable() { @Override public void run() { //操作安卓界面不能在单线程中,只能在主线程中,所以使用runOnUiThread中操作ui Toast.makeText(LoginActivity.this,"登录成功", Toast.LENGTH_SHORT).show(); } }); } else{ runOnUiThread(new Runnable() { @Override public void run() { //操作安卓界面不能在单线程中,只能在主线程中,所以使用runOnUiThread中操作ui try { Toast.makeText(LoginActivity.this,jsonObject.getString("msg"), Toast.LENGTH_SHORT).show(); } catch (JSONException e) { e.printStackTrace(); } } }); } }catch (Exception e){ e.printStackTrace(); } Looper.loop(); } }.start(); break; } } @Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode==8) { et_account.setFocusable(true); et_account.setFocusableInTouchMode(true); et_account.requestFocus(); Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { InputMethodManager inputManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputManager.showSoftInput(et_account, 0); } }, 200); } } }
Fragment(例子)
package com.ssa.seniorabilityassessment.fragment; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import androidx.fragment.app.Fragment; import androidx.viewpager.widget.PagerAdapter; import androidx.viewpager.widget.ViewPager; import com.ssa.seniorabilityassessment.R; import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class HomeFragment extends Fragment implements View.OnClickListener{ private View root; private ViewPager mViewPaper; private List<ImageView> images; private List<View> dots; private int currentItem; //记录上一次点的位置 private int oldPosition = 0; //存放图片的id private int[] imageIds = new int[]{ R.mipmap.ic_main1, R.mipmap.ic_main2 }; private ViewPagerAdapter adapter; private ScheduledExecutorService scheduledExecutorService; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { root=inflater.inflate(R.layout.fragment_home, container, false); initUI(); initData(); return root; } @Override public void onResume() { super.onResume(); initData1(); } @Override public void onHiddenChanged(boolean hidden) { // TODO Auto-generated method stub super.onHiddenChanged(hidden); initData1(); } private void initData1(){ } private void initUI(){ mViewPaper = root.findViewById(R.id.vp); //显示的图片 images = new ArrayList<ImageView>(); for(int i = 0; i < imageIds.length; i++){ ImageView imageView = new ImageView(getActivity()); imageView.setBackgroundResource(imageIds[i]); images.add(imageView); } //显示的小点 dots = new ArrayList<View>(); dots.add(root.findViewById(R.id.dot_0)); dots.add(root.findViewById(R.id.dot_1)); adapter = new ViewPagerAdapter(); mViewPaper.setAdapter(adapter); mViewPaper.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageSelected(int position) { dots.get(position).setBackgroundColor(getResources().getColor(R.color.blue)); dots.get(oldPosition).setBackgroundColor(getResources().getColor(R.color.grey1)); oldPosition = position; currentItem = position; } @Override public void onPageScrolled(int arg0, float arg1, int arg2) { } @Override public void onPageScrollStateChanged(int arg0) { } }); } private void initData(){ // btn_assess.setOnClickListener(this); // btn_info.setOnClickListener(this); // btn_senior.setOnClickListener(this); } @Override public void onClick(View v) { int id=v.getId(); Intent intent=new Intent(); switch (id){ // case R.id.tv_login: // if(sp.getString("phone",null)!=null){ // return; // } } } /*定义的适配器*/ public class ViewPagerAdapter extends PagerAdapter { @Override public int getCount() { return images.size(); } @Override public boolean isViewFromObject(View arg0, Object arg1) { return arg0 == arg1; } @Override public void destroyItem(ViewGroup view, int position, Object object) { // TODO Auto-generated method stub // super.destroyItem(container, position, object); // view.removeView(view.getChildAt(position)); // view.removeViewAt(position); view.removeView(images.get(position)); } @Override public Object instantiateItem(ViewGroup view, int position) { // TODO Auto-generated method stub view.addView(images.get(position)); return images.get(position); } } /** * 利用线程池定时执行动画轮播 */ @Override public void onStart() { // TODO Auto-generated method stub super.onStart(); scheduledExecutorService = Executors.newSingleThreadScheduledExecutor(); scheduledExecutorService.scheduleWithFixedDelay( new ViewPageTask(), 2, 2, TimeUnit.SECONDS); } /** * 图片轮播任务 * @author liuyazhuang * */ private class ViewPageTask implements Runnable{ @Override public void run() { currentItem = (currentItem + 1) % imageIds.length; mHandler.sendEmptyMessage(0); } } /** * 接收子线程传递过来的数据 */ private Handler mHandler = new Handler(){ public void handleMessage(android.os.Message msg) { mViewPaper.setCurrentItem(currentItem); }; }; @Override public void onStop() { // TODO Auto-generated method stub super.onStop(); if(scheduledExecutorService != null){ scheduledExecutorService.shutdown(); scheduledExecutorService = null; } } }
四.页面效果