目前网上主流的文章都是用底部的 RadioGroup + 页面部分的 Fragment 实现导航栏切换页面效果的。
然而底部的 RadioGroup 是如此麻烦,每个按钮的图片和文字部分都要做一个 selector 用于表示选中和非选中两种状态时的样式。
另外 Fragment 也有很多坑,先不管大家是否已熟练掌握,反正我是看着看着就学不下去了,所以我另辟蹊径用 Activity 的方式实现了伪 Fragment 的效果。
这里我们就来做一个三个按钮的底部导航栏。
因为我们这里是用三个 Activity 实现三个页面,而并非一个 Activity 中的三个 Fragment,所以在此之前,我们需要建立一个管理活动堆栈的类,以便在程序退出时能直接结束堆栈中的所有活动,不至于要依次退出三个 Activity。
在 java 代码目录里新建一个 base 包,在包内新建文件 AppManager.java:
/**
* AppManager: 用于对活动进行管理。
* 该模块仅限 base 包内使用。
* 该模块为单一实例,您需要调用 AppManager.get() 获取实例后再调用方法。
* <p>
* 为确保应用管理器正常工作,请新建一个继承 Activity 的抽象类 BaseActivity,
* 然后重写 BaseActivity 类的 onCreate() 和 onDestroy() 方法。
* 请给 BaseActivity 类的 onCreate() 方法添加如下代码:
* AppManager.get().addActivity(this);
* 请给 BaseActivity 类的 onDestroy() 方法添加如下代码:
* AppManager.get().removeActivity(this);
* 最后,确保本 APP 内的所有活动类均继承于 BaseActivity 类。
*/
class AppManager {
private static AppManager sManager = new AppManager();
private Stack<BaseActivity> mActivities;
private AppManager() {
// 将作用域关键字设置为 private 以隐藏该类的构造器。
// 该类的单例由 get() 方法引用。
// 创建单例的同时创建活动堆栈。
mActivities = new Stack<>();
} // AppManager() (Class Constructor)
/**
* get(): 获得 AppManager 类的单例。
*
* @return 该类的单例 sManager。
*/
static AppManager get() {
return sManager;
} // get()
/**
* addActivity(): 向堆栈中添加一个活动对象。
*
* @param activity 要添加的活动对象。
*/
void addActivity(BaseActivity activity) {
mActivities.add(activity);
} // addActivity()
/**
* removeActivity(): 从堆栈中移除一个活动对象。
*
* @param activity 要移除的活动对象。
*/
void removeActivity(BaseActivity activity) {
mActivities.remove(activity);
} // removeActivity()
/**
* finishAllExcept(): 除一个特定活动外,结束堆栈中其余所有活动。
* 结束活动时会触发 BaseActivity 类的 onDestroy()方法,
* 堆栈中的活动对象会同步移除。
*
* @param activityClass 要保留的活动的类名(xxxActivity.class)
*/
void finishAllExcept(Class activityClass) {
int i, len;
BaseActivity[] activities;
// 结束活动时会调用活动的 onDestroy() 方法,堆栈的内容会实时改变
// 为避免因此引起的引用错误,先将堆栈的内容复制到一个临时数组里
activities = mActivities.toArray(new BaseActivity[0]);
len = activities.length;
for (i = 0; i < len; ++i) {
if (!activities[i].getClass().equals(activityClass)) {
// 从数组里引用活动对象并结束,堆栈内容的改变不影响数组
activities[i].finish();
} // if (!activities[i].getClass().equals(activityClass))
} // for (i = 0; i < len; ++i)
} // finishAllExcept()
/**
* finishAllActivities(): 结束堆栈中的所有活动。
* 结束活动时会触发 BaseActivity 类的 onDestroy()方法,
* 堆栈中的活动对象会同步移除。
*/
void finishAllActivities() {
int i, len;
BaseActivity[] activities;
// 结束活动时会调用活动的 onDestroy() 方法,堆栈的内容会实时改变
// 为避免因此引起的引用错误,先将堆栈的内容复制到一个临时数组里
activities = mActivities.toArray(new BaseActivity[0]);
len = activities.length;
for (i = 0; i < len; ++i) {
// 从数组里引用活动对象并结束,堆栈内容的改变不影响数组
activities[i].finish();
} // for (i = 0; i < len; ++i)
} // finishAllActivities()
} // AppManager Class
// E.O.F
上述代码粘贴完后会报错,别着急,那是因为我们还没有建立和管理器相关联的 BaseActivity 类。现在我们在 base 包内再新建一个 BaseActivity.java,封装活动间的跳转方法。其中 jumpTo() 方法表示跳转后活动堆栈中只保留跳转后的那一个活动,压在堆栈中的其他活动全部销毁;而 open() 方法则保留活动堆栈。另外还有一个 showExitDialog() 的方法,用于询问用户是否退出程序,当用户选择“是”时,将堆栈中的所有活动一次性全部销毁。
/**
* BaseActivity: 该抽象类定义所有活动均拥有的共同属性。
* 本 APP 中所有活动对象均继承此类。
*/
public abstract class BaseActivity extends Activity {
/**
* onCreate(): 重写父类的 onCreate() 方法,向应用管理器中添加本活动。
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppManager.get().addActivity(this);
} // onCreate()
/**
* onDestroy(): 重写父类的 onDestroy() 方法,从应用管理器中移除本活动。
*/
@Override
protected void onDestroy() {
super.onDestroy();
AppManager.get().removeActivity(this);
} // onDestroy()
/**
* jumpTo(): 实现不传参的活动间跳转。
*
* @param dst 要跳转到的活动的类名(xxxActivity.class)。
*/
protected void jumpTo(Class dst) {
Intent intent = new Intent(this, dst);
startActivity(intent);
AppManager.get().finishAllExcept(dst);
} // jumpTo()
/**
* open(): 将当前活动压入堆栈,打开一个新活动。
*
* @param dst 要打开的活动的类名(xxxActivity.class)。
*/
protected void open(Class dst) {
Intent intent = new Intent(this, dst);
startActivity(intent);
} // open()
/**
* showExitDialog(): 显示退出程序对话框,询问用户是否退出程序。
*/
protected void showExitDialog() {
AlertDialog dialog;
DialogInterface.OnClickListener onClick;
onClick = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
// 确定按钮
dialog.dismiss();
AppManager.get().finishAllActivities();
break; // case DialogInterface.BUTTON_POSITIVE
case DialogInterface.BUTTON_NEGATIVE:
// 取消按钮
dialog.dismiss();
break; // case DialogInterface.BUTTON_NEGATIVE
default:
break; // default
} // switch (which)
} // onClick()