感觉这主页面这块还是比较复杂的,这段时间在学习这部分的源码,一遍遍的读源码,收获比较大的一部分是主页面四个Tab页面的展现形式。
这块儿借助了枚举类来完成相应的操作,是以前没有涉及过的,感觉很新鲜。
总体来说就是通过枚举类来列出5个Tab对应的内容页。在源码中初始化五个Tab页的代码如下所示:
//初始化底部的五个Tab页
private void initTabs() {
//调用枚举类MainTab的values方法,获得MainTab枚举类数组
MainTab[] tabs = MainTab.values();
final int size = tabs.length;
for (int i = 0; i < size; i++) {
//根据index获得具体对应的MainTab
MainTab mainTab = tabs[i];
//初始化每个Tab对应的图标、文字
TabSpec tab = mTabHost.newTabSpec(getString(mainTab.getResName()));
View indicator = LayoutInflater.from(getApplicationContext())
.inflate(R.layout.tab_indicator, null);
TextView title = (TextView) indicator.findViewById(R.id.tab_title);
Drawable drawable = this.getResources().getDrawable(
mainTab.getResIcon());
title.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null,
null);
if (i == 2) {
indicator.setVisibility(View.INVISIBLE);
mTabHost.setNoTabChangedTag(getString(mainTab.getResName()));
}
title.setText(getString(mainTab.getResName()));
tab.setIndicator(indicator);
tab.setContent(new TabContentFactory() {
@Override
public View createTabContent(String tag) {
return new View(MainActivity.this);
}
});
//为TabHost添加对应的页面内容
mTabHost.addTab(tab, mainTab.getClz(), null);
//如果对应的是我的界面则添加一个消息提醒的右上角图标。
if (mainTab.equals(MainTab.ME)) {
View cn = indicator.findViewById(R.id.tab_mes);
mBvNotice = new BadgeView(MainActivity.this, cn);
mBvNotice.setBadgePosition(BadgeView.POSITION_TOP_RIGHT);
mBvNotice.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
mBvNotice.setBackgroundResource(R.drawable.notification_bg);
mBvNotice.setGravity(Gravity.CENTER);
}
mTabHost.getTabWidget().getChildAt(i).setOnTouchListener(this);
}
}
在枚举类中来生成,代码如下:
package net.oschina.app.ui;
import net.oschina.app.R;
import net.oschina.app.fragment.ExploreFragment;
import net.oschina.app.fragment.MyInformationFragment;
import net.oschina.app.viewpagerfragment.NewsViewPagerFragment;
import net.oschina.app.viewpagerfragment.TweetsViewPagerFragment;
public enum MainTab {
//对应新闻页面
NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new,
NewsViewPagerFragment.class),
//对应动态页面
TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet,
TweetsViewPagerFragment.class),
//对应快速页面
QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new,
null),
//对应浏览页面
EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore,
ExploreFragment.class),
//对应“我”的页面
ME(4, R.string.main_tab_name_my, R.drawable.tab_icon_me,
MyInformationFragment.class);
//该枚举的页面index:0、1、2、3、4
private int idx;
//该枚举的页面的资源名字:综合、动弹、快速、发现、我
private int resName;
//每个枚举对应的icon
private int resIcon;
//每个枚举对应的Fragment的class
private Class<?> clz;
//枚举类的构造方法
private MainTab(int idx, int resName, int resIcon, Class<?> clz) {
this.idx = idx;
this.resName = resName;
this.resIcon = resIcon;
this.clz = clz;
}
public int getIdx() {
return idx;
}
public void setIdx(int idx) {
this.idx = idx;
}
public int getResName() {
return resName;
}
public void setResName(int resName) {
this.resName = resName;
}
public int getResIcon() {
return resIcon;
}
public void setResIcon(int resIcon) {
this.resIcon = resIcon;
}
public Class<?> getClz() {
return clz;
}
public void setClz(Class<?> clz) {
this.clz = clz;
}
}
ordinal()用来返回枚举值在枚举类中的顺序。
compareTo ()比较两个枚举值的顺序,返回顺序之差。
values(),静态方法,返回包含一个全部枚举值的数组。
toString(),返回枚举常量的名称
valueOf(),返回指定没弄成的枚举类型的枚举常量。
在JDK1.5 之前,我们定义常量都是: public static fianl…. 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。
public enum Color {
RED, GREEN, BLANK, YELLOW
}
JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
下面给出一个toString()方法覆盖的例子。
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//覆盖方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
}
所有的枚举都继承自java.lang.Enum类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour{
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumSet保证集合中的元素不重复;EnumMap中的key是enum类型,而value则可以是任意类型。关于这个两个集合的使用就不在这里赘述,可以参考JDK文档。
关于枚举的实现细节和原理请参考:
参考资料:《ThinkingInJava》第四版
参考文章:Java 枚举7常见种用法