FragmentTabHost + Fragment 實現(xiàn)底部菜單

一咬荷、實現(xiàn)效果

圖一

利用FragmentTabHost實現(xiàn)底部菜單困乒,在該底部菜單中斜友,包括了5個TabSpec,每個TabSpec中包含了一個View八秃,而View中包含了一個ImageView和一個TextView碱妆。而要在TabSpec中顯示這個View,就需要同過indicator來設置昔驱,eg:TabSpec.setIndicator(view);
二疹尾、動手實現(xiàn)

1、首先什么都不用說舍悯,先將準備好的5個TabSpec中的圖片復制到AS中Android目錄下的mipmap的文件夾中xxhdpi的文件夾下航棱。這里需要注意的是,每個TabSpec中應該都包含兩個圖標萌衬,一個是正常狀態(tài)的圖標(灰色的)饮醇,一個是該TabSpec被選中后的圖標(紅色的)。另外秕豫,為什么把圖片放在xxhdpi文件夾下而不是hdpi文件夾下朴艰?因為放在xxhdpi文件下的圖片顯示效果會比較細膩些, 圖標也顯得小一些混移。如果是把圖片放到hdpi文件夾下顯示出來的圖標就會比較粗糙祠墅,顯得比較大一個,顯示效果不夠好歌径。

2毁嗦、寫布局文件。在布局中需要使用到FragmentTabHost回铛,在Android開發(fā)者文檔中搜索FragmentTabHost狗准,顯示兩個克锣,一個是android.support.v4.app.FragmentTabHost,另外一個是android.support.v13.app.FragmentTabHost腔长。這里使用的是v4包下的FragmentTabHost袭祟。在使用前,需要添加相關的依賴捞附,這里導入的是com.android.support:support-v4:24.2.0巾乳。如果在就可以在actiivity-main布局文件中寫布局文件。其中需要注意的是鸟召,F(xiàn)ragmentTabHost的id是需要使用安卓自帶的id胆绊,“@android:id/tabhost”,而FragmentTabHost中的FrameLayout也需要使用安卓自帶的id药版,tabcontent辑舷。另外一點是,這個文件中有兩個FrameLayout槽片,因為實現(xiàn)的是底部菜單何缓,所以在FragmentTabHost中的FrameLayout是設置為0的,而FragmentTabHost真正需要顯示的內容是在上面的FrameLayout中進行顯示的还栓。布局文件如下所示:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              
              xmlns:tools="http://schemas.android.com/tools"              
              android:layout_width="match_parent"              
              android:layout_height="match_parent"              
              android:orientation="vertical"              
              tools:context=".MainActivity">    

   <FrameLayout        
              android:id="@+id/realcontent"        
              android:layout_width="match_parent"        
              android:layout_height="0dp"        
              android:layout_weight="1">    
    </FrameLayout>    

    <android.support.v4.app.FragmentTabHost        
              android:id="@android:id/tabhost"          
              android:layout_width="match_parent"        
              android:layout_height="wrap_content"        
              android:background="#ffffff" >      
 
         <FrameLayout         
               android:id="@android:id/tabcontent"            
               android:layout_width="0dp"            
               android:layout_height="0dp"            
               android:layout_weight="0" >
         </FrameLayout>    
     </android.support.v4.app.FragmentTabHost></LinearLayout>

3碌廓、在MainActivity中編寫邏輯。首先因為我們是使用FragmentTabHost+Fragment來實現(xiàn)的剩盒,所以需要讓MainActivity繼承FragmentActivity谷婆,注意繼承的這個FragmentActivity需要實在v4包下的。然后需要定義個FragmentTabHost辽聊,mTabHost纪挎,然后通過findViewById在視圖中找到這個FragmentTabHost。然后需要調用 mTabHost的setup()方法跟匆,該方法一般帶有3個參數(shù)异袄,
mTabHost.setup(this, getSupportFragmentManager(), R.id.realcontent);,其中注意的是第三個參數(shù)玛臂,是我需要真正使用的FrameLayout的id烤蜕。該方法的詳細介紹可以查閱Android開發(fā)者網(wǎng)站。接下來的步驟就是利用mTabHost new一個TabSpec出來迹冤。然后利用TabSpec讽营,setIndicator,最后就是講這個TabSpec加到mTabHost中泡徙。
其中setIncator方法中需要一個View橱鹏,因此需要編寫一個tab_indicator的xml文件,根據(jù)圖一發(fā)現(xiàn),其實只是一個ImageView蚀瘸,然后在ImageView下放一個TextView狡蝶。編寫起來也相對簡單。然后回到MainActivity中贮勃,利用LayoutInflater,將tab_indicator這個布局文件引入進來苏章,View view = mInflater.inflate(R.layout.tab_indicator,null),然后通過view.findViewById 找到其中的ImageView和TextView寂嘉,接著就對這兩個View進行賦值。
此外枫绅,將TabSpec加到TabHost中是調用mTabHost.addTab(tabSpec,HomeFragment.class, null);
由此可以看出泉孩,還需要一個HomeFragment類,此外這個類還需要一個布局文件并淋,這里主要是實現(xiàn)底部菜單寓搬,因此這個布局文件只是寫了個TextView。這個文件和這個代碼如下:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"              
              android:layout_width="match_parent"                      
              android:layout_height="match_parent"              
              android:gravity="center"              
              android:orientation="vertical">   

         <TextView        
              android:layout_width="wrap_content"            
              android:layout_height="wrap_content"        
              android:text="Home"       
              android:textSize="23sp"      
              android:textStyle="bold" />

</LinearLayout>
public class HomeFragment extends Fragment {    
      @Nullable    
      @Override    
       public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {       
             return inflater.inflate(R.layout.fragment_home,container,false);  
  }
}

3县耽、對代碼進行簡單的優(yōu)化
通過以上步驟就可以在底部菜單中實現(xiàn)一個圖標句喷,但是現(xiàn)在是要實現(xiàn)5個圖標的菜單。比較簡單兔毙、冗余的方法是唾琼,將剛才Activity中的代碼適當?shù)膹椭?份。但是這樣會讓代碼顯得冗余澎剥,而且不利于后期的維護锡溯,因此這里我們利用面向對象思想,對其中的一些經(jīng)常使用到的哑姚,會發(fā)生改變的內容進行封裝祭饭,將其封裝成一個類,然后實例化這個類的對象叙量,再通過調用這類的方法倡蝙,獲取相應的變量。這里我們定義一個Tab類宛乃。

public class Tab {   
      private int Image;    
      private int Text;    
      private Class Fragment;    

      public Tab(int image, int text, Class fragment) {        
              Image = image;       
              Text = text;       
              Fragment = fragment;    }    

      public int getImage() {        return Image;    }    
      public void setImage(int image) {        Image = image;    }          
      public int getText() {        return Text;    }    
      public void setText(int text) {        Text = text;    }    
      public Class getFragment() {        return Fragment;    }    
      public void setFragment(Class fragment) {        Fragment = fragment;    }
}

然后修改MainActivity中的內容

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.view.LayoutInflater;import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TabHost;
import android.widget.TextView;
import com.lyh.mymalll5.bean.Tab;
import com.lyh.mymalll5.fragment.CartFragment;
import com.lyh.mymalll5.fragment.DiscoverFragment;
import com.lyh.mymalll5.fragment.HomeFragment;
import com.lyh.mymalll5.fragment.HotFragment;
import com.lyh.mymalll5.fragment.UserFragment;
import java.util.ArrayList;

public class MainActivity extends FragmentActivity {    

      private FragmentTabHost mTabHost;    
      private LayoutInflater mInflater;    
      private ArrayList<Tab> mTabs= new ArrayList<Tab>(5);   

 @Override   
      protected void onCreate(Bundle savedInstanceState) {              
          super.onCreate(savedInstanceState);        
          setContentView(R.layout.activity_main);       
          initTab();   
 }    
      
      private void initTab() {        
          //實例化5個Tab類的對象        
          Tab Tab_home = new Tab(R.drawable.selector_home,R.string.home,HomeFragment.class);        
          Tab Tab_hot = new Tab(R.drawable.selector_hot,R.string.hot, HotFragment.class);        
          Tab Tab_discover = new Tab(R.drawable.selector_discover,R.string.discover, DiscoverFragment.class);        
          Tab Tab_cart = new Tab(R.drawable.selector_cart,R.string.cart, CartFragment.class);          
          Tab Tab_user = new Tab(R.drawable.selector_user,R.string.user, UserFragment.class);      

           //將這5個對象加到一個List中        
          mTabs.add(Tab_home);        
          mTabs.add(Tab_hot);        
          mTabs.add(Tab_discover);        
          mTabs.add(Tab_cart);        
          mTabs.add(Tab_user);        

          mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);        
          mTabHost.setup(this, getSupportFragmentManager(), R.id.realcontent);        
          mInflater = LayoutInflater.from(this);        

          //通過循環(huán)實例化一個個TabSpec        
          //并調用其中setIndicator方法        
          //然后將TabSpec加到TabHost中        
          for (Tab tab  :mTabs) {            
              TabHost.TabSpec tabSpec = mTabHost.newTabSpec(String.valueOf(tab.getText()));                  
              tabSpec.setIndicator(buildView(tab));            
              mTabHost.addTab(tabSpec,tab.getFragment(), null);        
            }        

           //通過這行代碼可以去除掉底部菜單5個圖表之間的分割線
           mTabHost.getTabWidget().setShowDividers(LinearLayout.SHOW_DIVIDER_NONE);    }    

          //設置Indicator中的View    
          private View buildView(Tab tab) {        
          View view = mInflater.inflate(R.layout.tab_indicator,null);        
          ImageView Tab_img = (ImageView) view.findViewById(R.id.tab_img);        
          TextView Tab_txt = (TextView) view.findViewById(R.id.tab_txt);        
          
          Tab_img.setBackgroundResource(tab.getImage());        
          Tab_txt.setText(tab.getText());        
          return view;    
        }
      }

4悠咱、簡單的優(yōu)化。通過上面步驟后征炼,基本上可以實現(xiàn)底部菜單的功能析既,但是僅僅如此的話,還是不夠全面谆奥,因為當點擊圖標的時候眼坏,圖標和文字都還不會變成紅色。首先設置圖標。
在Drawable文件下編寫5個xml文件宰译,這5個文件基本上是一樣檐蚜,都是設置成當被點的時候改變圖標,使用準備好的紅色的圖標沿侈。這里只給出其中的一個例子闯第。
selector_home.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android">    
          //被選中的時候的圖標
          <item android:state_selected="true" android:drawable="@mipmap/icon_home_press"/>    
          //正常狀態(tài)下的圖標
          <item android:drawable="@mipmap/icon_home"/>
</selector>

然后在實例化Tab類的對象的時候,在其函數(shù)中Image參數(shù)欄使用R.drawable.selector_home.xml文件就可缀拭。

而文字的該變更為簡單咳短,在res目錄下,新增一個color文件夾蛛淋,在該文件夾下增添一個text_color.xml文件咙好,在其中編寫被選中時的顏色的變化,這里只需編寫一個即可褐荷。

<selector xmlns:android="http://schemas.android.com/apk/res/android">    
    //被選中時候為紅色    
     <item android:color="#eb4f38" android:state_selected="true"/>    
    //正常情況下為灰色    
     <item android:color="#a9b7b7" android:state_selected="false"/>
</selector>

然后在tab_indicator.xml文件中的TextView控件中聲明textColor屬性為@color/text_color即可勾效。

最終實現(xiàn)的效果如下:

圖二
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市叛甫,隨后出現(xiàn)的幾起案子层宫,更是在濱河造成了極大的恐慌,老刑警劉巖合溺,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卒密,死亡現(xiàn)場離奇詭異,居然都是意外死亡棠赛,警方通過查閱死者的電腦和手機哮奇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來睛约,“玉大人鼎俘,你說我怎么就攤上這事”缋裕” “怎么了贸伐?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長怔揩。 經(jīng)常有香客問我捉邢,道長,這世上最難降的妖魔是什么商膊? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任伏伐,我火速辦了婚禮,結果婚禮上晕拆,老公的妹妹穿的比我還像新娘藐翎。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布吝镣。 她就那樣靜靜地躺著堤器,像睡著了一般。 火紅的嫁衣襯著肌膚如雪末贾。 梳的紋絲不亂的頭發(fā)上闸溃,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機與錄音未舟,去河邊找鬼圈暗。 笑死,一個胖子當著我的面吹牛裕膀,可吹牛的內容都是我干的。 我是一名探鬼主播勇哗,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼昼扛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了欲诺?” 一聲冷哼從身側響起抄谐,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扰法,沒想到半個月后蛹含,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡塞颁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年浦箱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祠锣。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡酷窥,死狀恐怖,靈堂內的尸體忽然破棺而出伴网,到底是詐尸還是另有隱情蓬推,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布澡腾,位于F島的核電站沸伏,受9級特大地震影響,放射性物質發(fā)生泄漏动分。R本人自食惡果不足惜毅糟,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刺啦。 院中可真熱鬧留特,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至右核,卻和暖如春慧脱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背贺喝。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工菱鸥, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人躏鱼。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓氮采,卻偏偏與公主長得像,于是被迫代替她去往敵國和親染苛。 傳聞我的和親對象是個殘疾皇子鹊漠,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349

推薦閱讀更多精彩內容