Android底部导航栏—FragmentTabHost+Fragment

来源:互联网 发布:淘宝打折后还显示原价 编辑:程序博客网 时间:2024/05/16 15:20

介绍

这里写图片描述
Android开发中使用底部菜单栏的频次非常高,主要的实现手段有以下:
- TabWidget
- 隐藏TabWidget,使用RadioGroup和RadioButton
- FragmentTabHost
- 5.0以后的TabLayout
- 最近推出的 Bottom navigation

案例1:简单使用

简单使用 FragmentTabHost
1 在布局文件使用 FragmentTabHost,并提供 Fragment 的容器
2 在 Activity 里查找 FragmentTabHost,并使用 setUp 方法关联到 Fragment 的容器
3 向 FragmentTabHost 里添加 Tab,注意 Tab 需要设置 indicate 文本
4 使用newInstance创建fragment
布局文件:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical"    tools:context="cn.itcast.demo.MainActivity">    <android.support.v7.widget.Toolbar        android:id="@+id/toolbar"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:background="#f0f">        <ImageView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_gravity="right"            android:layout_marginRight="10dp"            android:src="@drawable/actionbar_search_icon" />    </android.support.v7.widget.Toolbar>    <android.support.v4.widget.DrawerLayout        android:id="@+id/drawerlayout"        android:layout_width="match_parent"        android:layout_height="match_parent">        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:background="#f00"            android:orientation="vertical">            <FrameLayout                android:id="@+id/container"                android:layout_width="match_parent"                //特殊之处,高设置0dp  weight设置1                android:layout_height="0dp"                android:layout_weight="1"></FrameLayout>            <android.support.v4.app.FragmentTabHost                android:id="@+id/tabhost"                android:layout_width="match_parent"                android:layout_height="wrap_content" />        </LinearLayout>        <LinearLayout            android:layout_width="match_parent"            android:layout_height="match_parent"            android:layout_gravity="start"            android:background="#00f"></LinearLayout>    </android.support.v4.widget.DrawerLayout></LinearLayout>

MainActivity

public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);        setSupportActionBar(toolbar);        getSupportActionBar().setTitle("heihehie");        getSupportActionBar().setDisplayHomeAsUpEnabled(true);        DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawerlayout);        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.app_name,R.string.app_name);        drawerLayout.addDrawerListener(toggle);// 面板展开的监听设置给 Toogle        toggle.syncState();// 初始化 toogle 的绘制内容        // 设置底部栏        FragmentTabHost tabHost = (FragmentTabHost) findViewById(R.id.tabhost);        tabHost.setup(this,getSupportFragmentManager(),R.id.container);// 初始化 tabhost        // 添加一个 tab        TabHost.TabSpec tab1 = tabHost.newTabSpec("news");// 创建tab对象        tab1.setIndicator("资讯");// 设置tab 内容        Bundle arg = new Bundle();        arg.putString("content","资讯界面");        tabHost.addTab(tab1,TestFragment.class,arg);// 将tab添加到底部栏        // 再添加一个 Tab        TabHost.TabSpec tab2 = tabHost.newTabSpec("tweet");        tab2.setIndicator("动弹");        Bundle arg2 = new Bundle();        arg2.putString("content","动弹界面");        tabHost.addTab(tab2,TestFragment.class,arg2);    }    @Override    // 为 Activity 生成菜单,ToolBar已经被设置为标题栏,这个菜单会自动显示到 ToolBar 上    public boolean onCreateOptionsMenu(Menu menu) {        getMenuInflater().inflate(R.menu.activity_main,menu);        return super.onCreateOptionsMenu(menu);    }    @Override    // 目录菜单的点击响应    public boolean onOptionsItemSelected(MenuItem item) {        switch (item.getItemId()){            case R.id.menu_search:                Toast.makeText(this, "跳转到搜索界面", Toast.LENGTH_SHORT).show();                break;        }        return super.onOptionsItemSelected(item);    }}

TestFragment

public class TestFragment extends Fragment {    public static TestFragment newInstance(String content){        Bundle arg = getBundle(content);        TestFragment fragment = new TestFragment();        fragment.setArguments(arg);        return fragment;    }    @NonNull    public static Bundle getBundle(String content) {        Bundle arg = new Bundle();        arg.putString("content",content);        return arg;    }    @Nullable    @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        Bundle arg = getArguments();        String content = arg.getString("content");        TextView textView = new TextView(getActivity());        textView.setText(content);        return textView;    }}

案例 2

1.调用FragmentTabHost的setup方法;
2.创建TabHost.TabSpec对象,每一个对象对应一个item;
3.调用FragmentTabHost的addTab方法,把TabHost.TabSpec对象添加进来。
这里写图片描述
布局文件

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:orientation="vertical" >      <FrameLayout          android:id="@+id/realtabcontent"          android:layout_width="fill_parent"          android:layout_height="0dip"          android:layout_weight="1" />      <android.support.v4.app.FragmentTabHost          android:id="@android:id/tabhost"          android:layout_width="fill_parent"          android:layout_height="wrap_content" >          <FrameLayout              android:id="@android:id/tabcontent"              android:layout_width="0dp"              android:layout_height="0dp"              android:layout_weight="0" />      </android.support.v4.app.FragmentTabHost>  </LinearLayout> 

这个文件中需要注意的是,FragmentTabHost跟它里面的FrameLayout中的id都是引入的id,而真正的id写在FragmentTabHost外面的FrameLayout中
tab_item代码如下:

<?xml version="1.0" encoding="utf-8"?>  <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" >      <ImageView          android:id="@+id/imageview"          android:layout_width="wrap_content"          android:layout_height="wrap_content" >      </ImageView>      <TextView          android:id="@+id/textview"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:layout_marginTop="2dp"          android:textColor="@drawable/selector_tab_text" >      </TextView>  </LinearLayout>  

我们定义了五个子item,每个item对应一张图片跟一个标题,相信上面的布局大家都能看懂。每个item对应一个fragment,那么接下来我们把fragment的代码写出来,这里因为f五个ragment的代码差不多,我只给出HomeFragment的代码。fragment_home.xml布局文件如下:

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="match_parent"      android:layout_height="match_parent"      android:orientation="vertical" >      <TextView          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:text="首页Fragment"          android:textSize="20sp" />  </LinearLayout></span>  

HomeFragment.Java代码如下所示:

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

HomeFragment.java,这个里面不用讲吧,就是把fragment_home.xml文件中的内容填充到fragment中。接下来,我们还要继续写状态选择器selector,Eclipse在res下新建一个文件夹drawable,里面创建5个图片状态选择器跟一个文字状态选择器,这里图片状态选择器我只贴出一个,selector_icon_home.xml代码如下所示:

<?xml version="1.0" encoding="utf-8"?>  <selector xmlns:android="http://schemas.android.com/apk/res/android">      <!-- Non focused states -->      <item android:drawable="@drawable/icon_home" android:state_focused="false" android:state_pressed="false" android:state_selected="false"/>      <item android:drawable="@drawable/icon_home_press" android:state_focused="false" android:state_pressed="false" android:state_selected="true"/>      <!-- Focused states -->      <item android:drawable="@drawable/icon_home_press" android:state_focused="true" android:state_pressed="false" android:state_selected="false"/>      <item android:drawable="@drawable/icon_home_press" android:state_focused="true" android:state_pressed="false" android:state_selected="true"/>      <!-- Pressed -->      <item android:drawable="@drawable/icon_home_press" android:state_pressed="true" android:state_selected="true"/>      <item android:drawable="@drawable/icon_home_press" android:state_pressed="true"/>  </selector>

这里简单介绍一下,android:state_focused=”false”是没有聚焦状态,相反若为true,则为获得焦点状态。
android:state_pressed=”false”是没有按下状态,相反若为true,则为按下状态。
android;state_selected=”false”是没有被选择状态,相反则被选择。
最后,到了最重要的MainActivity,代码如下:

public class MainActivity extends FragmentActivity {      /**      * 定义FragmentTabHost对象      */      private FragmentTabHost mTabHost;      /**      * 定义一个布局填充器对象      */      private LayoutInflater mInflater;      /**      * 定义一个ArrayList来存放Tab      */      private List<Tab> mTabs = new ArrayList<Tab>(5);      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          requestWindowFeature(Window.FEATURE_NO_TITLE);          setContentView(R.layout.activity_main);          initTab();      }      /**      * 初始化Tab      */      private void initTab() {          Tab tab_home = new Tab(HomeFragment.class, R.string.home, R.drawable.selector_icon_home);          Tab tab_hot = new Tab(HotFragment.class, R.string.hot, R.drawable.selector_icon_hot);          Tab tab_category = new Tab(CategoryFragment.class, R.string.catagory, R.drawable.selector_icon_category);          Tab tab_cart = new Tab(CartFragment.class, R.string.cart, R.drawable.selector_icon_cart);          Tab tab_mine = new Tab(MineFragment.class, R.string.mine, R.drawable.selector_icon_mine);          mTabs.add(tab_home);          mTabs.add(tab_hot);          mTabs.add(tab_category);          mTabs.add(tab_cart);          mTabs.add(tab_mine);          mInflater = LayoutInflater.from(this);          mTabHost = (FragmentTabHost) this.findViewById(android.R.id.tabhost);          mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);          for (Tab tab : mTabs) {              TabHost.TabSpec tabSpec = mTabHost.newTabSpec(getString(tab.getTitle()));              tabSpec.setIndicator(buildIndicator(tab));              mTabHost.addTab(tabSpec, tab.getFragment(), null);          }      }      /**      * 给Tab设置图标跟文字      *       * @param tab      * @return      */      private View buildIndicator(Tab tab) {          View view = mInflater.inflate(R.layout.tab_item, null);          ImageView img = (ImageView) view.findViewById(R.id.imageview);          TextView text = (TextView) view.findViewById(R.id.textview);          img.setBackgroundResource(tab.getIcon());          text.setText(tab.getTitle());          return view;      }  }

看到MainActivity中的Tab了吗?我们创建一个package:com.example.fragmenttabhostdemo.bean,然后在该目录下新建一个java文件,Tab代码如下所示:

public class Tab {      private int title;      private int icon;      private Class fragment;      public Tab(Class fragment, int title, int icon) {          super();          this.title = title;          this.icon = icon;          this.fragment = fragment;      }      public int getTitle() {          return title;      }      public void setTitle(int title) {          this.title = title;      }      public int getIcon() {          return icon;      }      public void setIcon(int icon) {          this.icon = icon;      }      public Class getFragment() {          return fragment;      }      public void setFragment(Class fragment) {          this.fragment = fragment;      }  }  

案例3:彷新浪微博底部栏

这里写图片描述

1、主tab布局界面,main_tab_layout:

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"      android:layout_height="fill_parent"      android:orientation="vertical" >      <FrameLayout          android:id="@+id/realtabcontent"          android:layout_width="fill_parent"          android:layout_height="0dip"          android:layout_weight="1" />      <android.support.v4.app.FragmentTabHost          android:id="@android:id/tabhost"          android:layout_width="fill_parent"          android:layout_height="wrap_content"           android:background="@drawable/maintab_toolbar_bg">          <FrameLayout              android:id="@android:id/tabcontent"              android:layout_width="0dp"              android:layout_height="0dp"              android:layout_weight="0" />                  </android.support.v4.app.FragmentTabHost>  </LinearLayout>  

2、Tab按钮选项布局,tab_item_view.xml:

<?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="wrap_content"      android:layout_height="wrap_content"      android:gravity="center"      android:orientation="vertical" >      <ImageView          android:id="@+id/imageview"          android:layout_width="wrap_content"          android:layout_height="wrap_content"          android:focusable="false"          android:padding="3dp"           android:src="@drawable/tab_home_btn">      </ImageView>      <TextView          android:id="@+id/textview"                 android:layout_width="wrap_content"          android:layout_height="wrap_content"           android:text="首页"          android:textSize="10sp"          android:textColor="#ffffff">      </TextView>  </LinearLayout>  

3、fragment布局界面,这里只列出一个,fragment_1.xml:

<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"      android:layout_width="fill_parent"      android:layout_height="fill_parent" >      <ImageView          android:id="@+id/imageview"          android:layout_width="fill_parent"          android:layout_height="fill_parent"          android:scaleType="fitCenter"          android:src="@drawable/xianjian01" >      </ImageView>  </LinearLayout></span>  

4、Tab选项的自定义按钮资源文件,列出其中一个按钮,tab_home_btn:

<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  <selector xmlns:android="http://schemas.android.com/apk/res/android">      <item android:drawable="@drawable/icon_home_sel" android:state_selected="true"/>      <item android:drawable="@drawable/icon_home_nor"/>  </selector></span>  

5、Tab选项按钮背景资源文件,selector_tab_background.xml:

<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>  <selector xmlns:android="http://schemas.android.com/apk/res/android">      <item android:drawable="@drawable/home_btn_bg" android:state_pressed="true"/>      <item android:drawable="@drawable/home_btn_bg" android:state_selected="true"/>  </selector></span>  

6、主Activity类,MainTabActivity.Java:

public class MainTabActivity extends FragmentActivity{        //定义FragmentTabHost对象      private FragmentTabHost mTabHost;      //定义一个布局      private LayoutInflater layoutInflater;      //定义数组来存放Fragment界面      private Class fragmentArray[] = {FragmentPage1.class,FragmentPage2.class,FragmentPage3.class,FragmentPage4.class,FragmentPage5.class};      //定义数组来存放按钮图片      private int mImageViewArray[] = {R.drawable.tab_home_btn,R.drawable.tab_message_btn,R.drawable.tab_selfinfo_btn,                                       R.drawable.tab_square_btn,R.drawable.tab_more_btn};      //Tab选项卡的文字      private String mTextviewArray[] = {"首页", "消息", "好友", "广场", "更多"};      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main_tab_layout);          initView();      }      /**      * 初始化组件      */      private void initView(){          //实例化布局对象          layoutInflater = LayoutInflater.from(this);          //实例化TabHost对象,得到TabHost          mTabHost = (FragmentTabHost)findViewById(android.R.id.tabhost);          mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);           //得到fragment的个数          int count = fragmentArray.length;             for(int i = 0; i < count; i++){                //为每一个Tab按钮设置图标、文字和内容              TabSpec tabSpec = mTabHost.newTabSpec(mTextviewArray[i]).setIndicator(getTabItemView(i));              //将Tab按钮添加进Tab选项卡中              mTabHost.addTab(tabSpec, fragmentArray[i], null);              //设置Tab按钮的背景              mTabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.drawable.selector_tab_background);          }      }      /**      * 给Tab按钮设置图标和文字      */      private View getTabItemView(int index){          View view = layoutInflater.inflate(R.layout.tab_item_view, null);          ImageView imageView = (ImageView) view.findViewById(R.id.imageview);          imageView.setImageResource(mImageViewArray[index]);          TextView textView = (TextView) view.findViewById(R.id.textview);                  textView.setText(mTextviewArray[index]);          return view;      }  }

7、Fragment页面,FragmentPage1.java:

public class FragmentPage1 extends Fragment{      @Override      public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {                return inflater.inflate(R.layout.fragment_1, null);           }     }  

案例4:顶部栏导航

这里写图片描述
主要包括:
(1) 自定义Tab的图片资源和去掉分割线.
(2) 缓存Fragment的布局, 减少填充.
在切换页面时, 控件会调用Fragment的onCreateView, 重新创建页面.
通过缓存页面, 可以增强性能.
1. 布局

FragmentTabHost是原生控件, 并不需要添加其他的maven库.
包括标签组Tabs和页面TabContainer, 标签组固定大小, 页面填充.

<?xml version="1.0" encoding="utf-8"?><android.support.v4.app.FragmentTabHost    android:id="@android:id/tabhost"    xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <LinearLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical">        <TabWidget            android:id="@android:id/tabs"            android:layout_width="match_parent"            android:layout_height="?attr/actionBarSize"            android:layout_gravity="bottom"/>        <FrameLayout            android:id="@android:id/tabcontent"            android:layout_width="match_parent"            android:layout_height="0dp"            android:layout_weight="1"/>    </LinearLayout></android.support.v4.app.FragmentTabHost>

注意控件的id必须是Android提供的标准id, 即”@android:id”.
Fragment布局, 包含一行文字提示.

<?xml version="1.0" encoding="utf-8"?><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">    <TextView        android:id="@+id/tab_tv_text"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:gravity="center"        android:textSize="40sp"        tools:text="Test"/></LinearLayout>

Tab布局, 包含一个图片控件.

<?xml version="1.0" encoding="utf-8"?><LinearLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="wrap_content"    android:layout_height="wrap_content"    android:orientation="vertical">    <ImageView        android:id="@+id/tab_iv_image"        android:padding="12dp"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:contentDescription="@null"        tools:src="@drawable/tab_assistant"/></LinearLayout>

2. 主页

setup设置页面组合, 却掉分割线etDividerDrawable(null), 设置Tab.
使用自定义的图片资源, newTabSpec设置Fragment的Tag标签.

/** * 主页, 切换Tab标签显示不同页面. * * @author C.L.Wang */public class MainActivity extends AppCompatActivity {    @Bind(android.R.id.tabhost) FragmentTabHost mTabHost;    // 图片    @DrawableRes    private int mImages[] = {            R.drawable.tab_counter,            R.drawable.tab_assistant,            R.drawable.tab_contest,            R.drawable.tab_center    };    // 标题    private String mFragmentTags[] = {            "counter",            "assistant",            "contest",            "center"    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        ButterKnife.bind(this);        mTabHost.setup(this, getSupportFragmentManager(), android.R.id.tabcontent);        mTabHost.getTabWidget().setDividerDrawable(null); // 去掉分割线        for (int i = 0; i < mImages.length; i++) {            // Tab按钮添加文字和图片            TabHost.TabSpec tabSpec = mTabHost.newTabSpec(mFragmentTags[i]).setIndicator(getImageView(i));            // 添加Fragment            mTabHost.addTab(tabSpec, FragmentTab.class, null);            // 设置Tab按钮的背景            mTabHost.getTabWidget().getChildAt(i).setBackgroundResource(R.color.pedo_actionbar_bkg);        }    }    // 获得图片资源    private View getImageView(int index) {        @SuppressLint("InflateParams")        View view = getLayoutInflater().inflate(R.layout.view_tab_indicator, null);        ImageView imageView = (ImageView) view.findViewById(R.id.tab_iv_image);        imageView.setImageResource(mImages[index]);        return view;    }}

3. 切换页

显示不同Tag标签. 缓存页面, 注意关联前, 删除父控件关联. 页面显示Tag信息.

public class FragmentTab extends Fragment {    @Bind(R.id.tab_tv_text) TextView mTvText;    private View mViewContent; // 缓存视图内容    @Nullable @Override    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {        if (mViewContent == null) {            mViewContent = inflater.inflate(R.layout.fragment_tab, container, false);        }        // 缓存View判断是否含有parent, 如果有需要从parent删除, 否则发生已有parent的错误.        ViewGroup parent = (ViewGroup) mViewContent.getParent();        if (parent != null) {            parent.removeView(mViewContent);        }        ButterKnife.bind(this, mViewContent);        return mViewContent;    }    @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {        super.onViewCreated(view, savedInstanceState);        // 显示Fragment的Tag信息        mTvText.setText(String.valueOf("Page: " + getTag()));    }    @Override public void onDestroyView() {        super.onDestroyView();        ButterKnife.unbind(this);    }}
0 0