今天,我将总结一下Android应用中大家经常见到的底部导航栏的几种实现!
一。TabHost + RadioGroup实现方式
在我们平时开发过程中使用的TabHost是在上方,这里我们简单修改了一下<TabHost>的布局,让叶片放到了底部。
main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<?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
1
2
3
4
5
6
7
8
9
|
<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
1
2
3
4
5
|
<?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类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
<?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类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
<?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界面都需继承它)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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!大功告成!相当实用的!有兴趣的可以学习一下!
源码下载:http://down.51cto.com/data/1009354
今天,我将总结一下Android应用中大家经常见到的底部导航栏的几种实现!
一。TabHost + RadioGroup实现方式
在我们平时开发过程中使用的TabHost是在上方,这里我们简单修改了一下<TabHost>的布局,让叶片放到了底部。
main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
<?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
1
2
3
4
5
6
7
8
9
|
<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
1
2
3
4
5
|
<?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类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
<?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类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
<?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界面都需继承它)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
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()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
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!大功告成!相当实用的!有兴趣的可以学习一下!
源码下载:http://down.51cto.com/data/1009354
本文转自zhf651555765 51CTO博客,原文链接:http://blog.51cto.com/smallwoniu/1324123,如需转载请自行联系原作者