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(); } }
大致就這么多,因為是將兩個布局雜糅在一塊,如果有問題可以在博客后面進行留言,