Android学习系列(23)--App主界面实现
在上篇文章《Android学习系列(22)--App主界面比较》中我们浅略的分析了几个主界面布局,选了一个最大众化的经典布局。
今天我们就这个经典布局,用代码具体的实现它。
1.预览图
先看下最终的界面设计图:
上面顶部是一个9patch背景图片+标题文字;
下面底部是5个tab标签,表示应用的5大模块。
中间内容部分则是各个模块的具体内容,可以再分类,或者直接显示内容。
2.准备素材
按照上篇文章的界面,我们需要事先提供两大方面的素材:顶部+底部。
顶部的素材非常简单,最重要的是背景(9patch的图片):
底部的素材稍微多一点:
(1).每个tab的背景都需要正常和选中两种,一共10张图片;
(2).每个tab之间有一张分割线,1张图片;
(3).为了自适应屏幕宽度,并保持图形不变形,必须tab背景和下面botton这个背景色一致,所以需要1张同背景的背景图片。
如下:
(1).
(2).
(3).
在这里呢,我再三考量,决定还是把图片和文字放在一起,这样一能大大降低代码的复杂性,而且能保证漂亮的样式,我们通过Photoshop来控制,灵活性大大增强。
以上是我在网上随便找了几张照片,稍微处理了一下,作为下面我们实现的素材。
3.实现原理
这里,我采用了getDecorView方法,发现这种方法布局和代码比较简洁,看上去性能也不错(待查)。
用核心代码来说明一下原理:
1
2
3
4
5
6
|
//mainTabContainer是一个空布局,做为每个tab的容器 //activity是每个tab对应的activity //getDecorView是对应的activity的视图,添加到tab容器中,就能实现切换activity的效果了 mainTabContainer.removeAllViews(); mainTabIntent = new Intent( this ,activity); mainTabContainer.addView(localActivityManager.startActivity(id, mainTabIntent).getDecorView()); |
通过切换不同的activity的decorView,实现tab的视图切换。
4.基本框架
布局界面思路非常清晰,顶部+底部+中间tab内容
我采用相对布局(相对于线性布局,我经常选择帧布局和相对布局,我更喜欢这两个小巧的布局):
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
|
android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < LinearLayout android:id = "@+id/main_tab_banner" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:paddingLeft = "10dip" android:orientation = "horizontal" android:gravity = "center" android:background = "@drawable/main_banner_bg" android:layout_alignParentTop = "true" > <!-- 标题 --> </ LinearLayout > < LinearLayout android:id = "@+id/main_tab" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:orientation = "horizontal" android:gravity = "center" android:background = "@drawable/tab_bg" android:layout_alignParentBottom = "true" > <!-- 内容 --> </ LinearLayout > < LinearLayout android:id = "@+id/main_tab_container" android:layout_above = "@id/main_tab" android:layout_below = "@id/main_tab_banner" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:background = "#FFFFE0" > </ LinearLayout > </ RelativeLayout > |
看起来很复杂的东西,分解一下就简单的多了。
在标题处,加上一个TextView,做为标题显示。
在内容处,我们需要填充5个Tab背景和1个分割线,请参考《Android学习系列(5)--App布局初探之简单模型》 中的模型四,使用了layout_weight的属性,平均分割了5个tab.
最终我们的布局文件如下:
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
|
<? xml version = "1.0" encoding = "utf-8" ?> android:orientation = "vertical" android:layout_width = "fill_parent" android:layout_height = "fill_parent" > < LinearLayout android:id = "@+id/main_tab_banner" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:paddingLeft = "10dip" android:orientation = "horizontal" android:gravity = "center" android:background = "@drawable/main_banner_bg" android:layout_alignParentTop = "true" > < TextView android:id = "@+id/main_tab_banner_title" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:text = "欣赏美花" android:textSize = "20dip" android:textColor = "#000000" /> </ LinearLayout > < LinearLayout android:id = "@+id/main_tab" android:layout_width = "fill_parent" android:layout_height = "wrap_content" android:orientation = "horizontal" android:gravity = "center" android:background = "@drawable/tab_bg" android:layout_alignParentBottom = "true" > < ImageView android:id = "@+id/appreciate_tab_btn" android:layout_weight = "1" android:layout_width = "wrap_content" android:layout_height = "fill_parent" android:gravity = "center_horizontal|bottom" android:src = "@drawable/appreciate_press" /> < ImageView android:gravity = "center" android:layout_gravity = "center_vertical" android:layout_width = "5dip" android:layout_height = "wrap_content" android:src = "@drawable/tab_split" /> < ImageView android:id = "@+id/discuss_tab_btn" android:layout_weight = "1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center_horizontal|bottom" android:textSize = "16dip" android:src = "@drawable/discuss_normal" android:textColor = "#000000" /> < ImageView android:gravity = "center" android:layout_gravity = "center_vertical" android:layout_width = "5dip" android:layout_height = "wrap_content" android:src = "@drawable/tab_split" /> < ImageView android:id = "@+id/identification_tab_btn" android:layout_weight = "1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center_horizontal|bottom" android:textSize = "16dip" android:src = "@drawable/identification_normal" android:textColor = "#000000" /> < ImageView android:gravity = "center" android:layout_gravity = "center_vertical" android:layout_width = "5dip" android:layout_height = "wrap_content" android:src = "@drawable/tab_split" /> < ImageView android:id = "@+id/favorite_tab_btn" android:layout_weight = "1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center_horizontal|bottom" android:textSize = "16dip" android:textColor = "#000000" android:src = "@drawable/favorite_normal" /> < ImageView android:gravity = "center" android:layout_gravity = "center_vertical" android:layout_width = "5dip" android:layout_height = "wrap_content" android:src = "@drawable/tab_split" /> < ImageView android:id = "@+id/setting_tab_btn" android:layout_weight = "1" android:layout_width = "wrap_content" android:layout_height = "wrap_content" android:gravity = "center_horizontal|bottom" android:textSize = "16dip" android:src = "@drawable/setting_normal" android:textColor = "#000000" /> </ LinearLayout > < LinearLayout android:id = "@+id/main_tab_container" android:layout_above = "@id/main_tab" android:layout_below = "@id/main_tab_banner" android:layout_width = "fill_parent" android:layout_height = "fill_parent" android:background = "#FFFFE0" > </ LinearLayout > </ RelativeLayout > |
其中的main_tab_container是容器布局,到时候动态存放切换的activity的视图。
这时候,效果图如下:
中间的内容为空,tab点击也没有任何效果,我们继续实现。
这就是布局文件main_tab_frame.xml.
5.事件效果
现在我们把点击效果,切换标题,这些效果关联起来。
选择不同的tab,显示不同的标题,同时切换不同的activity.
以点击评花的主要代码为例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
//评花 discussImageView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { //标题 mainTabTitleTextView.setText( "评花论花" ); //切换内容 setContainerView( "discuss" , DiscussTabActivity. class ); //切换tab页背景 appreciateImageView.setImageResource(R.drawable.appreciate_normal); discussImageView.setImageResource(R.drawable.discuss_press); identificationImageView.setImageResource(R.drawable.identification_normal); favoriteImageView.setImageResource(R.drawable.favorite_normal); settingImageView.setImageResource(R.drawable.setting_normal); } }); //切换activity public void setContainerView(String id,Class<?> activity){ mainTabContainer.removeAllViews(); mainTabIntent = new Intent( this ,activity); mainTabContainer.addView(localActivityManager.startActivity(id, mainTabIntent).getDecorView()); } |
我们继承ActivityGroup这个类,实现这个完整的类MainTabFrame.java:
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
113
114
115
116
117
118
119
|
public class MainTabFrame extends ActivityGroup { //Tab Activity Layout private LocalActivityManager localActivityManager = null ; private LinearLayout mainTabContainer = null ; private Intent mainTabIntent = null ; //Tab banner title private TextView mainTabTitleTextView = null ; //Tab ImageView private ImageView appreciateImageView = null ; private ImageView discussImageView = null ; private ImageView identificationImageView = null ; private ImageView favoriteImageView = null ; private ImageView settingImageView = null ; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); setContentView(R.layout.main_tab_frame); mainTabContainer = (LinearLayout)findViewById(R.id.main_tab_container); localActivityManager = getLocalActivityManager(); setContainerView( "appreciate" , AppreciateTabActivity. class ); initTab(); } /** * 初始化Tab项 */ private void initTab() { mainTabTitleTextView = (TextView)findViewById(R.id.main_tab_banner_title); appreciateImageView = (ImageView)findViewById(R.id.appreciate_tab_btn); discussImageView = (ImageView)findViewById(R.id.discuss_tab_btn); identificationImageView = (ImageView)findViewById(R.id.identification_tab_btn); favoriteImageView = (ImageView)findViewById(R.id.favorite_tab_btn); settingImageView = (ImageView)findViewById(R.id.setting_tab_btn); //赏花 appreciateImageView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { mainTabTitleTextView.setText( "欣赏美花" ); setContainerView( "appreciate" , AppreciateTabActivity. class ); appreciateImageView.setImageResource(R.drawable.appreciate_press); discussImageView.setImageResource(R.drawable.discuss_normal); identificationImageView.setImageResource(R.drawable.identification_normal); favoriteImageView.setImageResource(R.drawable.favorite_normal); settingImageView.setImageResource(R.drawable.setting_normal); } }); //评花 discussImageView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { mainTabTitleTextView.setText( "评花论花" ); setContainerView( "discuss" , DiscussTabActivity. class ); appreciateImageView.setImageResource(R.drawable.appreciate_normal); discussImageView.setImageResource(R.drawable.discuss_press); identificationImageView.setImageResource(R.drawable.identification_normal); favoriteImageView.setImageResource(R.drawable.favorite_normal); settingImageView.setImageResource(R.drawable.setting_normal); } }); //识花 identificationImageView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { mainTabTitleTextView.setText( "亮眼识花" ); setContainerView( "identification" , IdentificationTabActivity. class ); appreciateImageView.setImageResource(R.drawable.appreciate_normal); discussImageView.setImageResource(R.drawable.discuss_normal); identificationImageView.setImageResource(R.drawable.identification_press); favoriteImageView.setImageResource(R.drawable.favorite_normal); settingImageView.setImageResource(R.drawable.setting_normal); } }); //收藏 favoriteImageView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { mainTabTitleTextView.setText( "我的收藏" ); setContainerView( "favorite" , FavoriteTabActivity. class ); appreciateImageView.setImageResource(R.drawable.appreciate_normal); discussImageView.setImageResource(R.drawable.discuss_normal); identificationImageView.setImageResource(R.drawable.identification_normal); favoriteImageView.setImageResource(R.drawable.favorite_press); settingImageView.setImageResource(R.drawable.setting_normal); } }); //设置 settingImageView.setOnClickListener( new OnClickListener() { @Override public void onClick(View v) { mainTabTitleTextView.setText( "定义设置" ); setContainerView( "setting" , SettingTabActivity. class ); appreciateImageView.setImageResource(R.drawable.appreciate_normal); discussImageView.setImageResource(R.drawable.discuss_normal); identificationImageView.setImageResource(R.drawable.identification_normal); favoriteImageView.setImageResource(R.drawable.favorite_normal); settingImageView.setImageResource(R.drawable.setting_press); } }); } public void setContainerView(String id,Class<?> activity){ mainTabContainer.removeAllViews(); mainTabIntent = new Intent( this ,activity); mainTabContainer.addView(localActivityManager.startActivity(id, mainTabIntent).getDecorView()); } } |
具体的每个activity怎么显示的,再通过AppreciateTabActivity,DiscussTabActivity,IdentificationTabActivity,FavoriteTabActivity,SettingTabActivity这些独自实现,不再累述。
6.扩展建议
这里补充两点:
(1).标题栏在上述示例中,我是放在MainTabFrame,这样做的好处是,统一了,方便了;这样做的缺点是,如果每个activity的标题栏是不同的按钮,不同的操作,会有些膨胀。所以,标题栏放在主Acvtivity和子Activity中,考虑一下即可。
(2).tab的切换效果,我做的非常简单,具体的图片阴影,凹凸,文字色彩区分都没有去做(本人对Photoshop实在不熟),美化方面还可以大大改进。
7.小结
通过实现这么个简单的主界面框架,能使我们快速的开始我们相应的感兴趣项目,提供了一种大众化得参考,是android学习者必备基础。
这种东西的积累和分析也是能提高我们感觉应用的审美感。