首頁-底部Tab導航(選單欄)的實現:FragmentTabHost+ViewPager+Fragment
前言
Android開發中使用底部選單欄的頻次非常高,主要的實現手段有以下:
- TabWidget
- 隱藏TabWidget,使用RadioGroup和RadioButton
- FragmentTabHost
- 5.0以後的TabLayout
- 最近推出的 Bottom navigation
今天帶大家來探索下如何用Fragment+FragmentTabHost++ViewPager
實現底部選單欄
目錄
總體設計思路
- Fragment:存放不同選項的頁面內容
- FragmentTabHost:點選切換選項卡
- ViewPager:實現頁面的左右滑動效果
概念介紹
1. FragmentTabHost
用於實現點選選項進行切換選項卡的自定義效果
使用FragmentTabHost,就是先用TabHost“裝著”Fragment,然後放進MainActivity裡面
2. ViewPager
- 定義
ViewPager是android擴充套件包v4包中的類
android.support.v4.view.ViewPager
- 作用
左右切換當前的view,實現滑動切換的效果。
注:
1.ViewPager類直接繼承了ViewGroup類,和LinearLayout等佈局一樣,都是一個容器,需要在裡面新增我們想要顯示的內容。
2.ViewPager類需要PagerAdapter介面卡類提供資料,與ListView類似 3.Google官方建議ViewPager配合Fragment使用
具體使用請參考我寫的另外一篇文章:Android開發:ViewPage的介紹
3. Fragment
- 定義
Fragment是activity的介面中的一部分或一種行為
1.把Fragment認為模組化的一段activity
2.它具有自己的生命週期,接收它自己的事件,並可以在activity執行時被新增或刪除
3.Fragment不能獨立存在,它必須嵌入到activity中,而且Fragment的生命週期直接受所在的activity的影響。例如:當activity暫停時,它擁有的所有的Fragment們都暫停了,當activity銷燬時,它擁有的所有Fragment們都被銷燬。
- 作用
主要是為了支援更動態、更靈活的介面設計(從3.0開始引入)
底部選單欄實現步驟
- 在主xml佈局裡面定義一個FragmentTabHost控制元件
- 定義底部選單欄佈局
- 定義每個Fragment佈局
- 定義每個Fragment的Java類
- 定義介面卡以關聯頁卡和ViewPage
- 定義MainActivity(具體實現請看註釋)
具體實現例項
1. 完整Demo下載地址
2. 工程檔案目錄
3. 具體實現步驟
步驟1:在主xml佈局裡面定義一個FragmentTabHost控制元件
主xml佈局:Main_tab_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<include layout="@layout/main_top" />
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" /><!--裝4個Fragment-->
<FrameLayout
android:visibility="gone"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1" />
<!--定義FragmentTabHost控制元件-->
<android.support.v4.app.FragmentTabHost
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:color/black" ><!--裝4個Fragment-->
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0" /><!--裝Tab的內容-->
</android.support.v4.app.FragmentTabHost>
</RelativeLayout>
步驟2:定義底部選單欄佈局
tab_content.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:gravity="center"
android:orientation="vertical"
android:background="#ffffff">
<ImageView
android:id="@+id/tab_imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
<TextView
android:id="@+id/tab_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@drawable/selector_text_background" />
</LinearLayout>
步驟3:定義Fragment佈局
fragment_item1.xml&fragment_item2.xml
這裡使用兩個選項,由於fragment_item1.xml與fragment_item2.xml相同,這裡只貼出一個
fragment_item1.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="fragment1"
android:textSize="20sp"/>
</LinearLayout>
步驟4: 定義每個Fragment的Java類
- 這裡使用兩個選項:Fragment1.java&fragmen2.java
- 由於Fragment1.java&fragmen2.java相同,這裡只貼出一個
Fragment1.java
package com.example.carson_ho.tab_menu_demo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by Carson_Ho on 16/5/23.
*/
public class Fragment1 extends Fragment
{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_item1, null);
return view;
}
}
步驟5: 定義介面卡關聯頁卡和ViewPage
MyFragmentAdapter.java
package com.example.carson_ho.tab_menu_demo;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import java.util.List;
/**
* Created by Carson_Ho on 16/5/23.
*/
public class MyFragmentAdapter {extends FragmentPagerAdapter
{
List<Fragment> list;
public MyFragmentAdapter(FragmentManager fm,List<Fragment> list) {
super(fm);
this.list=list;
}//寫構造方法,方便賦值呼叫
@Override
public Fragment getItem(int arg0) {
return list.get(arg0);
}//根據Item的位置返回對應位置的Fragment,繫結item和Fragment
@Override
public int getCount() {
return list.size();
}//設定Item的數量
}
步驟6: 定義MainActivity
具體實現看註釋
MainActivity.java
package com.example.carson_ho.tab_menu_demo;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentTabHost;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TabHost;
import android.widget.TabWidget;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends FragmentActivity implements
ViewPager.OnPageChangeListener, TabHost.OnTabChangeListener {
private FragmentTabHost mTabHost;
private LayoutInflater layoutInflater;
private Class fragmentArray[] = { Fragment1.class, Fragment2.class };
private int imageViewArray[] = { R.drawable.tab_home_btn, R.drawable.tab_view_btn };
private String textViewArray[] = { "首頁", "分類"};
private List<Fragment> list = new ArrayList<Fragment>();
private ViewPager vp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();//初始化控制元件
initPage();//初始化頁面
}
// 控制元件初始化控制元件
private void initView() {
vp = (ViewPager) findViewById(R.id.pager);
/*實現OnPageChangeListener介面,目的是監聽Tab選項卡的變化,然後通知ViewPager介面卡切換介面*/
/*簡單來說,是為了讓ViewPager滑動的時候能夠帶著底部選單聯動*/
vp.addOnPageChangeListener(this);//設定頁面切換時的監聽器
layoutInflater = LayoutInflater.from(this);//載入佈局管理器
/*例項化FragmentTabHost物件並進行繫結*/
mTabHost = (FragmentTabHost) findViewById(android.R.id.tabhost);//繫結tahost
mTabHost.setup(this, getSupportFragmentManager(), R.id.pager);//繫結viewpager
/*實現setOnTabChangedListener介面,目的是為監聽介面切換),然後實現TabHost裡面圖片文字的選中狀態切換*/
/*簡單來說,是為了當點選下面選單時,上面的ViewPager能滑動到對應的Fragment*/
mTabHost.setOnTabChangedListener(this);
int count = textViewArray.length;
/*新建Tabspec選項卡並設定Tab選單欄的內容和繫結對應的Fragment*/
for (int i = 0; i < count; i++) {
// 給每個Tab按鈕設定標籤、圖示和文字
TabHost.TabSpec tabSpec = mTabHost.newTabSpec(textViewArray[i])
.setIndicator(getTabItemView(i));
// 將Tab按鈕新增進Tab選項卡中,並繫結Fragment
mTabHost.addTab(tabSpec, fragmentArray[i], null);
mTabHost.setTag(i);
mTabHost.getTabWidget().getChildAt(i)
.setBackgroundResource(R.drawable.selector_tab_background);//設定Tab被選中的時候顏色改變
}
}
/*初始化Fragment*/
private void initPage() {
Fragment1 fragment1 = new Fragment1();
Fragment2 fragment2 = new Fragment2();
list.add(fragment1);
list.add(fragment2);
//繫結Fragment介面卡
vp.setAdapter(new MyFragmentAdapter(getSupportFragmentManager(), list));
mTabHost.getTabWidget().setDividerDrawable(null);
}
private View getTabItemView(int i) {
//將xml佈局轉換為view物件
View view = layoutInflater.inflate(R.layout.tab_content, null);
//利用view物件,找到佈局中的元件,並設定內容,然後返回檢視
ImageView mImageView = (ImageView) view
.findViewById(R.id.tab_imageview);
TextView mTextView = (TextView) view.findViewById(R.id.tab_textview);
mImageView.setBackgroundResource(imageViewArray[i]);
mTextView.setText(textViewArray[i]);
return view;
}
@Override
public void onPageScrollStateChanged(int arg0) {
}//arg0 ==1的時候表示正在滑動,arg0==2的時候表示滑動完畢了,arg0==0的時候表示什麼都沒做,就是停在那。
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
}//表示在前一個頁面滑動到後一個頁面的時候,在前一個頁面滑動前呼叫的方法
@Override
public void onPageSelected(int arg0) {//arg0是表示你當前選中的頁面位置Postion,這事件是在你頁面跳轉完畢的時候呼叫的。
TabWidget widget = mTabHost.getTabWidget();
int oldFocusability = widget.getDescendantFocusability();
widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);//設定View覆蓋子類控制元件而直接獲得焦點
mTabHost.setCurrentTab(arg0);//根據位置Postion設定當前的Tab
widget.setDescendantFocusability(oldFocusability);//設定取消分割線
}
@Override
public void onTabChanged(String tabId) {//Tab改變的時候呼叫
int position = mTabHost.getCurrentTab();
vp.setCurrentItem(position);//把選中的Tab的位置賦給介面卡,讓它控制頁面切換
}
}
效果圖
經過上述6個步驟就完成了可滑動的底部選單欄了,效果圖如下:
實現步驟彙總
底部選單欄實現步驟:
1. 在主xml佈局裡面定義一個FragmentTabHost控制元件
2. 定義底部選單欄佈局
3. 定義每個Fragment佈局
4. 定義每個Fragment的Java類
5. 定義介面卡以關聯頁卡和ViewPage
6. 定義具體實現的MainActivity
完整Demo下載地址
總結
本文對底部選單欄進行了全面的實現,也講解得非常詳細,有不懂的可以直接在下面留言給我哦!接下來我會介紹繼續介紹Android開發中的相關知識,有興趣可以繼續關注Carson_Ho的安卓部落格