今天,我将总结一下Android应用中大家经常见到的底部导航栏的几种实现!
一。TabHost + RadioGroup实现方式
在我们平时开发过程中使用的TabHost是在上方,这里我们简单修改了一下<TabHost>的布局,让叶片放到了底部。
main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0" />
<RadioGroup
android:id="@+id/radioGroup"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="@drawable/bar"
android:gravity="center_vertical"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/rd_home"
style="@style/main_btn_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/home_icon"
android:text="主页" />
<RadioButton
android:id="@+id/rd_wt"
style="@style/main_btn_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/wb_icon_write_n"
android:text="发表" />
<RadioButton
android:id="@+id/rd_msg"
style="@style/main_btn_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/msg_icon"
android:text="信息" />
<RadioButton
android:id="@+id/rd_more"
style="@style/main_btn_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/more_icon"
android:text="更多" />
</RadioGroup>
</LinearLayout>
</TabHost>
styles.xml
<style name="main_btn_style">
<item name="android:button">@null</item>
<item name="android:textSize">10dp</item>
<item name="android:textColor">#ffffff</item>
<item name="android:gravity">center_horizontal</item>
<item name="android:drawablePadding">4dp</item>
<item name="android:layout_weight">1.0</item>
<item name="android:background">@drawable/main_btn_bg_d</item>
</style>
main_btn_bg_d.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/main_btn_bg" android:state_enabled="true" android:state_pressed="true"></item>
<item android:drawable="@drawable/main_btn_bg" android:state_checked="true" android:state_enabled="true"></item>
</selector>
这里需要注意的是:
1.main.xml中:TabWidget的id必须是@android:id/tabs,FrameLayout的id必须是 @android:id/tabcontent。
2.把TabWidget的Visibility设置成了gone!也就是默认难看的风格不见了:
,取而代之的是5个带风格的单选按钮.
MainActivity类
package com.zhf.android_tabhost;import android.app.TabActivity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.TabHost;
import android.widget.TabHost.TabSpec;
public class MainActivity extends TabActivity {
private TabHost tabHost;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tabHost = this.getTabHost();
TabSpec homeSpec = tabHost.newTabSpec("home").setIndicator("home").setContent(new Intent(this,HomeActivity.class));
TabSpec writeSpec = tabHost.newTabSpec("write").setIndicator("write").setContent(new Intent(this,WriteActivity.class));
TabSpec msgSpec = tabHost.newTabSpec("msg").setIndicator("msg").setContent(new Intent(this,MsgActivity.class));
TabSpec moreSpec = tabHost.newTabSpec("more").setIndicator("more").setContent(new Intent(this,MoreActivity.class));
tabHost.addTab(homeSpec);
tabHost.addTab(writeSpec);
tabHost.addTab(msgSpec);
tabHost.addTab(moreSpec);
RadioGroup rg = (RadioGroup) this.findViewById(R.id.radioGroup);
rg.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
switch (checkedId) {
case R.id.rd_home:
tabHost.setCurrentTabByTag("home");
break;
case R.id.rd_wt:
tabHost.setCurrentTabByTag("write");
break;
case R.id.rd_msg:
tabHost.setCurrentTabByTag("msg");
break;
case R.id.rd_more:
tabHost.setCurrentTabByTag("more");
break;
default:
break;
}
}
});
}
}
注:
1.由于TabWidget被隐藏,所以相关的事件也会无效,这里取巧用RadioGroup与RadioButton的特性来处理切换,然后监听事件调用setCurrentTabByTag来切换Activity。
2.注意即使TabWidget被隐藏,也要为其设置indicator,否则会保持。
效果图:
(点击底部就可以实现切换不同的Activity的操作了,这里需要注意的一点是,切换底部菜单时不会重新调用onCreate()方法的!!)
二.底部回调接口实现(使用Fragment)--- 重要!
这种方式使用了最新的Fragment,采用了底部导航栏回调接口的方法,来切换底部菜单,并且每次切换回重新调用onCreate()方法!!
main.xml:
<?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="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:orientation="vertical" >
<RelativeLayout
android:id="@+id/main_title_RelativeLayout"
android:layout_width="fill_parent"
android:layout_height="50dp"
android:background="@drawable/fragment_bottom_normal"
android:orientation="horizontal" >
<TextView
android:id="@+id/main_title_TextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主页"
android:textColor="@android:color/white"
android:textSize="24sp" />
</RelativeLayout>
<FrameLayout
android:id="@+id/main_detail_FrameLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffffff" >
</FrameLayout>
</LinearLayout>
<fragment
android:id="@+id/bottom_fragment"
android:name="com.zhf.frameworkdemo02.fragments.BottomFragment"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
这里由于我们底部菜单我们采用了fragment,所以布局里面要留出位置!
BottomFragment类:
package com.zhf.frameworkdemo02.fragments;import com.zhf.frameworkdemo02.R;
import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RadioGroup;
import android.widget.RadioGroup.OnCheckedChangeListener;
/**
* 页面底部导航栏
*
* @author ZHF
*
*/
public class BottomFragment extends Fragment {
//默认回调接口实现类的对象
private Callbacks callbacks = defaultCallbacks;
/** Fragment和Activity建立关联的时候调用 **/
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//当前类是否实现了底部导航栏点击事件回调接口
if(!(activity instanceof Callbacks)) {
throw new IllegalStateException("Activity must implements fragment's callbacks !");
}
callbacks = (Callbacks) activity;
}
/** 为Fragment加载布局时调用 **/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
RadioGroup radioGroup = (RadioGroup) inflater.inflate(R.layout.fragment_bottom, container, false);
//绑定监听器
radioGroup.setOnCheckedChangeListener(changeListener);
return radioGroup;
}
/**RadioGroup监听器**/
private OnCheckedChangeListener changeListener = new OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
System.out.println(checkedId);
callbacks.onItemSelected(checkedId); //调用接口中方法
}
};
public interface Callbacks{
/**导航栏回调接口**/
public void onItemSelected(int item);
}
/**默认回调实现类的对象**/
private static Callbacks defaultCallbacks = new Callbacks() {
@Override
public void onItemSelected(int item) {
//什么都不干
}
};
/**Fragment和Activity解除关联的时候调用**/
@Override
public void onDetach() {
super.onDetach();
callbacks = defaultCallbacks;
}
}
底部菜单布局fragment_bottom.xml
<?xml version="1.0" encoding="utf-8"?><RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal" >
<RadioButton
android:id="@+id/fragment_bottom_home"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="@drawable/fragment_bottom_selector"
android:button="@null"
android:drawableTop="@drawable/main_readiobutton_home"
android:gravity="center"
android:text="@string/home"
android:textColor="@color/white"
android:textSize="12sp" />
<View
android:layout_width="1dp"
android:layout_height="fill_parent"
android:background="@color/white" />
<RadioButton
android:id="@+id/fragment_bottom_order"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="@drawable/fragment_bottom_selector"
android:button="@null"
android:drawableTop="@drawable/main_readiobutton_order"
android:gravity="center"
android:text="@string/order"
android:textColor="@color/white"
android:textSize="12sp" />
<View
android:layout_width="1dp"
android:layout_height="fill_parent"
android:background="@color/white"
/>
<RadioButton
android:id="@+id/fragment_bottom_notice"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="@drawable/fragment_bottom_selector"
android:button="@null"
android:drawableTop="@drawable/main_readiobutton_notice"
android:gravity="center"
android:text="@string/notice"
android:textColor="@color/white"
android:textSize="12sp" />
<View
android:layout_width="1dp"
android:layout_height="fill_parent"
android:background="@color/white" />
<RadioButton
android:id="@+id/fragment_bottom_more"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:background="@drawable/fragment_bottom_selector"
android:button="@null"
android:drawablePadding="3dip"
android:drawableTop="@drawable/main_readiobutton_more"
android:gravity="center"
android:text="@string/more"
android:textColor="@color/white"
android:textSize="12sp" />
</RadioGroup>
这里我们定义了一个框架类:GeneralFragment(所有的fragment界面都需继承它)
package com.zhf.frameworkdemo02.fragments;
import java.io.Serializable;
import com.zhf.frameworkdemo02.R;
import com.zhf.frameworkdemo02.view.OrderView;
import com.zhf.frameworkdemo02.view.HomeView;
import com.zhf.frameworkdemo02.view.MoreView;
import com.zhf.frameworkdemo02.view.NoticeView;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* 框架类,抽象公共方法
* @author ZHF
*
*/
public class GeneralFragment extends Fragment implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private int item; //用于区分底部菜单项
protected static View main_title_RelativeLayout; //标题栏
protected final static String key = "Bundle"; //跳转值传递key的名称
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
if(getArguments() != null) { //根据接收子类传来的arguments判断item的哪一项
if(getArguments().containsKey(MainFragment.Item)) {
item = getArguments().getInt(MainFragment.Item);
}
}
}
/**为Fragment加载布局时调用 **/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_general, container, false);
GeneralFragment fragment = null;
switch(item) {
case R.id.fragment_bottom_home: //初始化主页
fragment = new HomeView();
break;
case R.id.fragment_bottom_order:
fragment = new OrderView(); //初始化订单
break;
case R.id.fragment_bottom_notice:
fragment = new NoticeView(); //初始化公告
break;
case R.id.fragment_bottom_more:
fragment = new MoreView(); //初始化更多
break;
default:
break;
}
if(fragment != null) {
//更换mainView中间的内容(home,msg,at,more)
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.general_fragment, fragment).commit();
}
main_title_RelativeLayout = ((View) container.getParent()).findViewById(R.id.main_title_RelativeLayout);
//将生成的view返回
return view;
}
/**设置标题**/
protected void setTitle(Object title) {
if(main_title_RelativeLayout != null) {
//标题栏中的文字
TextView mTvTitle = (TextView) main_title_RelativeLayout.findViewById(R.id.main_title_TextView);
if(mTvTitle != null) {
if(title instanceof Integer) { //整型
mTvTitle.setText((Integer)title);
} else { //字符类型
mTvTitle.setText((CharSequence)title);
}
}
}
}
/**页面跳转值传递**/
protected void setBundle(Object... objects) {
Bundle arguments = new Bundle();
arguments.putSerializable(key, objects);
GeneralFragment generalFragment = new GeneralFragment();
generalFragment.setArguments(arguments);
}
/**获取所传递的值**/
protected Object[] getBundle() {
if(getArguments() != null) {
System.out.println("getBundle");
if(getArguments().containsKey(key)) {
Object[] object = (Object[]) getArguments().getSerializable(key);
return object;
}
}
return null;
}
/**无参页面跳转**/
protected void toIntent(GeneralFragment generalFragment) {
if(generalFragment != null) {
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.general_fragment, generalFragment).commit();
}
}
}
程序入口MainFragment:
package com.zhf.frameworkdemo02.fragments;import com.zhf.frameworkdemo02.R;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
/**
*MainView
* @author ZHF
*
*/
public class MainFragment extends FragmentActivity implements BottomFragment.Callbacks {
public final static String Item = "item";
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//初始化默认调用接口中item选中方法
onItemSelected(R.id.fragment_bottom_home);
}
@Override
public void onItemSelected(int item) {
Bundle arguments = new Bundle();
arguments.putInt(Item, item); //将选中的底部radio的Id放进去
GeneralFragment generalFragment = new GeneralFragment();
generalFragment.setArguments(arguments); //设置参数值
//这里根据item的ID进行界面跳转
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.main_detail_FrameLayout, generalFragment).commit();
}
}
说明:这里我们的每个界面都将采用Fragment,故每个界面需重写onCreateView()
package com.zhf.frameworkdemo02.view;import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.zhf.frameworkdemo02.R;
import com.zhf.frameworkdemo02.fragments.GeneralFragment;
/**
* 主页面
* @author ZHF
*
*/
public class HomeView extends GeneralFragment{
@Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
super.setTitle("主页");
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.home, container, false);
}
}
(其他三个略)
最终效果图:
ok!大功告成!相当实用的!有兴趣的可以学习一下!
转载于:https://blog.51cto.com/smallwoniu/1324123