android自带的有TabHost,但好像无法满足要求,
本文只记录使用 TabLayout + Fragment 和 android 自带的 BottomNavigationView + Fragment 来实现
由于测试的时候使用的是一个工程,所以看起来可能有点乱,但是里面的工程目录没有变化,变化的只是代码部分
需要新建的部分如下:
新建一个工程,如果是在做项目,不要在原项目中进行操作,以免损坏原项目,
通用部分,Fragment部分,(xml和对应的java代码),Androidstudio中会自带代码,不需要改动里面的代码
添加对应的包依赖
menu是 BottomNavigationView + Fragment需要的,如果工程中不使用自带的新建的话,可以不需要建立这一部分,
接下来先介绍 TabLayout + Fragment :
主页面的布局代码,
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 xmlns:app="http://schemas.android.com/apk/res-auto" 4 android:orientation="vertical" 5 android:layout_width="match_parent" 6 android:layout_height="match_parent"> 7 8 <FrameLayout 9 android:id="@+id/home_container" 10 android:layout_width="match_parent" 11 android:layout_height="0dp" 12 android:layout_weight="1" 13 > 14 </FrameLayout> 15 16 <View android:layout_width="match_parent" 17 android:layout_height="0.5dp" 18 android:alpha="0.6" 19 android:background="@android:color/darker_gray" 20 /> 21 <android.support.design.widget.TabLayout 22 android:id="@+id/bottom_tab_layout" 23 android:layout_width="match_parent" 24 app:tabIndicatorHeight="0dp" 25 app:tabSelectedTextColor="@android:color/black" 26 app:tabTextColor="@android:color/darker_gray" 27 android:layout_height="48dp"> 28 <!--app:menu="@menu/tab_menu" 如果需要使用 BottomNavigationView + Fragment 布局的话取消注释,更改id即可--> 29 30 </android.support.design.widget.TabLayout> 31 32 </LinearLayout>
3 import android.content.Context; 4 import android.support.v4.app.Fragment; 5 import android.view.LayoutInflater; 6 import android.view.View; 7 import android.widget.ImageView; 8 import android.widget.TextView; 9 10 import com.example.tabhostcostom.AttentionFragment; 11 import com.example.tabhostcostom.DiscoveryFragment; 12 import com.example.tabhostcostom.HomeFragment; 13 import com.example.tabhostcostom.ProfileFragment; 14 import com.example.tabhostcostom.R; 15 16 public class DataGenerator { 17 18 public static final int []mTabRes = new int[]{R.mipmap.index_blue_icon, R.mipmap.index_message, R.mipmap.index_publish, R.mipmap.index_ying, R.mipmap.index_me}; 19 //public static final int []mTabResPressed = new int[]{R.drawable.ic_tab_strip_icon_feed_selected,R.drawable.ic_tab_strip_icon_category_selected,R.drawable.ic_tab_strip_icon_pgc_selected,R.drawable.ic_tab_strip_icon_profile_selected}; 20 public static final String []mTabTitle = new String[]{"首页","发现","", "关注","我的"}; 21 22 public static Fragment[] getFragments(String from){ 23 Fragment fragments[] = new Fragment[4]; 24 fragments[0] = HomeFragment.newInstance(from, "a"); 25 fragments[1] = DiscoveryFragment.newInstance(from, "b"); 26 fragments[2] = AttentionFragment.newInstance(from, "c"); 27 fragments[3] = ProfileFragment.newInstance(from, "d"); 28 return fragments; 29 } 30 31 /** 32 * 获取Tab 显示的内容 33 * @param context 34 * @param position 35 * @return 36 */ 37 public static View getTabView(Context context, int position){ 38 View view = LayoutInflater.from(context).inflate(R.layout.home_tab_content,null); 39 ImageView tabIcon = view.findViewById(R.id.tab_content_image); 40 tabIcon.setImageResource(DataGenerator.mTabRes[position]); 41 TextView tabText = view.findViewById(R.id.tab_content_text); 42 tabText.setText(mTabTitle[position]); 43 return view; 44 } 45 }
以上是一个工具类将所有的数据全部封装在一块,
我也没搞明白为什么需要传两个参数,应该是可以改的吧,自己没有尝试,随便传一个字符串即可,
主函数中也就是主页面的代码
1 import android.net.Uri; 2 import android.support.annotation.Nullable; 3 import android.support.design.widget.BottomNavigationView; 4 import android.support.annotation.NonNull; 5 import android.support.design.widget.TabLayout; 6 import android.support.v4.app.Fragment; 7 import android.support.v7.app.AppCompatActivity; 8 import android.os.Bundle; 9 import android.view.MenuItem; 10 import android.view.View; 11 import android.widget.ImageView; 12 import android.widget.TextView; 13 import android.widget.Toast; 14 15 import com.example.tabhostcostom.Utils.DataGenerator; 16 17 public class MainActivity extends AppCompatActivity implements HomeFragment.OnFragmentInteractionListener, DiscoveryFragment.OnFragmentInteractionListener , 18 AttentionFragment.OnFragmentInteractionListener, ProfileFragment.OnFragmentInteractionListener 19 { 20 21 private BottomNavigationView mBottomNavigationView; 22 //private Fragment []mFragments; 23 private TabLayout mTabLayout; 24 private Fragment []mFragmensts; 25 26 @Override 27 protected void onCreate(@Nullable Bundle savedInstanceState) { 28 super.onCreate(savedInstanceState); 29 setContentView(R.layout.activity_main); 30 31 mFragmensts = DataGenerator.getFragments("TabLayout Tab"); 32 33 initView(); 34 } 35 36 private void initView() { 37 mTabLayout = findViewById(R.id.bottom_tab_layout); 38 39 mTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() { 40 @Override 41 public void onTabSelected(TabLayout.Tab tab) { 42 onTabItemSelected(tab.getPosition()); 43 // Tab 选中之后,改变各个Tab的状态,如果点击下面的导航栏,需要改变颜色的话取消注释,同时取消掉工具类中的注释即可 44 /* 45 for (int i=0;i<mTabLayout.getTabCount();i++){ 46 View view = mTabLayout.getTabAt(i).getCustomView(); 47 ImageView icon = (ImageView) view.findViewById(R.id.tab_content_image); 48 TextView text = (TextView) view.findViewById(R.id.tab_content_text); 49 50 if(i == tab.getPosition()){ // 选中状态 51 icon.setImageResource(DataGenerator.mTabResPressed[i]); 52 text.setTextColor(getResources().getColor(android.R.color.black)); 53 }else{// 未选中状态 54 icon.setImageResource(DataGenerator.mTabRes[i]); 55 text.setTextColor(getResources().getColor(android.R.color.darker_gray)); 56 } 57 }*/ 58 59 60 } 61 62 @Override 63 public void onTabUnselected(TabLayout.Tab tab) { 64 65 } 66 67 @Override 68 public void onTabReselected(TabLayout.Tab tab) { 69 70 } 71 }); 72 73 for(int i=0;i<5;i++){ 74 mTabLayout.addTab(mTabLayout.newTab().setCustomView(DataGenerator.getTabView(this,i))); 75 } 76 77 } 78 79 private void onTabItemSelected(int position){ 80 Fragment fragment = null; 81 switch (position){ 82 case 0: 83 fragment = mFragmensts[0]; 84 break; 85 case 1: 86 fragment = mFragmensts[1]; 87 break; 88 case 2: 89 fragment = mFragmensts[2]; 90 break; 91 case 3: 92 fragment = mFragmensts[3]; 93 break; 94 case 4: 95 fragment = mFragmensts[3]; 96 break; 97 } 98 if(fragment!=null) { 99 getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit(); 100 } 101 } 102 103 @Override 104 public void onFragmentInteraction(Uri uri) { 105 Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show(); 106 } 107 }
这是 TabLayout + Fragment 全部代码
下面介绍 BottomNavigationView + Fragment 实现,带有动画效果,点击的那个会自动将其他的挤出去,所以建议使用上面的布局方式,当然,需要动画效果的布局也可以
需要 menu 菜单
1 <?xml version="1.0" encoding="utf-8"?> 2 <menu xmlns:android="http://schemas.android.com/apk/res/android"> 3 <item 4 android:id="@+id/tab_menu_home" 5 android:icon="@mipmap/index_blue_icon" 6 android:title="首页" 7 /> 8 <item 9 android:id="@+id/tab_menu_discovery" 10 android:icon="@mipmap/index_message" 11 android:title="发现" 12 /> 13 <item 14 android:id="@+id/tab_menu_attention1" 15 android:icon="@mipmap/index_publish" 16 android:title="" 17 /> 18 <item 19 android:id="@+id/tab_menu_profile" 20 android:icon="@mipmap/index_ying" 21 android:title="Ying" 22 /> 23 <item 24 android:id="@+id/tab_menu_attention" 25 android:icon="@mipmap/index_me" 26 android:title="我" 27 /> 28 29 </menu>
主函数中代码:
package com.example.tabhostcostom; import android.net.Uri; import android.support.annotation.Nullable; import android.support.design.widget.BottomNavigationView; import android.support.annotation.NonNull; import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MenuItem; import android.view.View; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; import com.example.tabhostcostom.Utils.DataGenerator; public class MainActivity extends AppCompatActivity implements HomeFragment.OnFragmentInteractionListener, DiscoveryFragment.OnFragmentInteractionListener , AttentionFragment.OnFragmentInteractionListener, ProfileFragment.OnFragmentInteractionListener { private BottomNavigationView mBottomNavigationView; private Fragment []mFragments; private TabLayout mTabLayout; private Fragment []mFragmensts; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mFragments = DataGenerator.getFragments("TabLayout Tab"); initView(); } private void initView() { mBottomNavigationView = findViewById(R.id.bottom_navigation_view); //mBottomNavigationView.getMaxItemCount() mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(@NonNull MenuItem item) { onTabItemSelected(item.getItemId()); return true; } }); // 由于第一次进来没有回调onNavigationItemSelected,因此需要手动调用一下切换状态的方法 onTabItemSelected(R.id.tab_menu_home); } private void onTabItemSelected(int id){ Fragment fragment = null; switch (id){ case R.id.tab_menu_home: fragment = mFragments[0]; break; case R.id.tab_menu_discovery: fragment = mFragments[1]; break; case R.id.tab_menu_attention: fragment = mFragments[2]; break; case R.id.tab_menu_profile: fragment = mFragments[3]; break; } if(fragment!=null) { getSupportFragmentManager().beginTransaction().replace(R.id.home_container,fragment).commit(); } } @Override public void onFragmentInteraction(Uri uri) { Toast.makeText(this, "hello", Toast.LENGTH_SHORT).show(); } }
大致就这么多,因为是将两个布局杂糅在一块,如果有问题可以在博客后面进行留言,