使用 Paginize 编写 Android 应用
GitHub - neevek/Paginize: Paginize is a light-weight application framework for Android.
Paginize 是一个轻量级的 Android 应用框架,它提供了对项目充分模块化的支持,使得开发者能够最大程度地复用代码。它的设计初衷是想通过更好的组织代码结构,把复杂的问题简单化,提高代码的复用率、可维护性和加快开发周期,同时摆脱一个界面对应一个 Activity 的窘境。
Paginize 把一个屏幕上的内容的管理操作封装成一个 Page, 在某些场景下,一个 Page 的内容可能会比较复杂,可以把屏幕上的部分内容封装成一个 InnerPage,多个 InnerPage 可以被嵌套到一个 ContainerPage(ContainerPage 是 Page 的子类) 中。Paginize 提供了不同 Page 之间切换的 API,提供了『布局继承』等功能。
Paginize 可以被用于现有项目(因为它只需要一个 Activity 作为容器)和全新项目。目前最新版是 0.6.1,可通过 Gradle 引入依赖:
dependencies {
compile net.neevek.android:paginize:0.6.1
}
下面是使用 Paginize 编写的例子,主要演示『布局继承』、界面切换和相关注解(Annotation)的使用。
- 创建一个 BasePage 使用的布局文件(R.layout.page_base),这个布局使用了 Support Library 的 Toolbar 控制项,用于实现 Material Design 的标题栏。内容区域是一个 FrameLayout,继承 BasePage 的子类可以把内容填充到这个 FrameLayout 中实现不同的界面。
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width_="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:background="#fff"
>
<android.support.design.widget.AppBarLayout
android:id="@+id/appBar"
android:layout_width_="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.v7.widget.Toolbar
android:id="@+id/tb_header_bar"
android:layout_width_="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/layout_content_container"
android:layout_width_="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
/>
</android.support.design.widget.CoordinatorLayout>
- 创建抽象类 BasePage,继承自 Page。这里用抽象类是因为我们不太可能直接使用一个 BasePage,因为它所提供的功能并不完整,它只有一个标题栏和一个内容容器。在这个类里面,使用了 @PageLayout 注解把布局文件和 BasePage 进行了关联,这样在 BasePage 中就可以通过 @InjectView 注解注入 View,也可以直接使用 findViewById 获取这个布局中的 View 了。
// 通过 @PageLayout 注解把布局文件 R.layout.page_base.xml
// 和当前的 BasePage 进行关联,这样在 BasePage
@PageLayout(R.layout.page_base)
public abstract class BasePage extends Page {
@InjectView(R.id.tb_header_bar)
private Toolbar mTbToolbar;
public BasePage(PageActivity pageActivity) {
super(pageActivity);
// Page 栈上的 Page 数量如果大于 1,
// 就启用 Toolbar 左上角的返回按钮
if (getContext().getPageCount() > 1) {
ToolbarHelper.setNavigationIconEnabled(mTbToolbar, true, new View.OnClickListener() {
@Override
public void onClick(View v) {
onNavigationIconClicked(v);
}
});
}
}
// 提供给子类设置当前界面的标题
protected final void setTitle(String title) {
mTbToolbar.setTitle(title);
}
// 提供给子类设置右上角的菜单,菜单是跟 Page 绑定的,
// 而不是跟 Activity 绑定的
protected final void setupMenu(@MenuRes int menuResId) {
ToolbarHelper.setupMenu(mTbToolbar, menuResId, new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
return BasePage.this.onMenuItemClick(item);
}
});
}
protected void onNavigationIconClicked(View v) {
// 关闭当前的 Page(从 Page 栈上删除当前 Page)
hide(true);
}
// 子类可以覆盖此方法处理右上角菜单按钮事件
protected boolean onMenuItemClick(MenuItem item) {
return false;
}
// 提供给子类直接操作 Toolbar 的途径
protected final Toolbar getToolbar() {
return mTbToolbar;
}
}
- 再创建一个用于实现具体功能的 Page 与其对应的布局文件(R.layout.page_hello),这个界面很简单,只有标题栏和中间的一个 TextView 用于显示 『Hello Paginize!』,标题栏是继承自 BasePage 的,所以这个布局文件里面只需要一个 TextView:
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_hello"
android:layout_width_="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:textSize=「28sp"
android:padding="10dip"
/>
- HelloPage 也很简单,继承 BasePage,通过使用 @InsertPageLayout 指定关联的布局文件,再通过指定的 parent 属性,把当前布局插入到 BasePage 的 R.id.layout_content_container 元素中(这里的 parent 属性是可选的,如果不指定,当前布局就会被插到 BasePage 布局最后一个元素的位置)。通过以上的继承,HelloPage 只需要实现其对 TextView 的操作就可以了。
@InsertPageLayout(value = R.layout.page_test, parent = R.id.layout_content_container)
public class HelloPage extends BasePage {
@InjectView(R.id.tv_hello)
private TextView mTvHello;
public TestPage(PageActivity pageActivity) {
super(pageActivity);
setTitle("Hello Paginize!");
mTvHello.setText("Hello Paginize!");
}
}
- 最后要把这个 HelloPage 显示出来,我们还需要一个 Activity,这个 Activity 需要继承 PageActivity(PageActivity 通过使用 PageManager 对 Page 栈的进行管理)。对于 PageActivity,可以使用 @InjectPageAnimator 注解指定 Page 的过场动画,开发者也可以自定义自己的 PageAnimator 实现不同的过场动画效果。注:目前 Paginize 也提供了类似微信的过场动画效果,但暂时不是通过 @InjectPageAnimator 实现,而是通过调用 PaginizeManager.enableSwipeToHide() 和 PaginizeManager.useSwipePageTransitionEffect() 来实现的。
@InjectPageAnimator(SlidePageAnimator.class)
public class MainActivity extends PageActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 使用类似微信过场动画效果,调用这两个方法之后
// @InjectPageAnimator 设置的 PageAnimator 将被忽略
// getPageManager().enableSwipeToHide();
// getPageManager().useSwipePageTransitionEffect();
// 显示 HelloPage
new HelloPage(this).show(true);
}
}
- 效果
上面的例子演示了通过『布局继承』,实现一个包含具体业务功能(显示 Hello Paginize!)的 Page,这个 Page 的代码很简单,只包含了对其本身 TextView 的操作,与具体业务无关的功能都在父类中实现,且只需要实现一次。这里的 Page 扮演著 Controller 的角色。
看到这里,你可能会拿它跟 Fragment 做比较,对此我不敢对 Fragment 做过多评价,因为实际上我并没怎么用过 Fragment,Paginize 的雏形早在 2012 年就在公司的项目中用过,当时我还不知道有 Support Library 这个东西(说来真是惭愧)。所以比较就只能让 Fragment 的深度用户去做啦
想了解 Paginize 更多的功能和更完整的例子,可以直接 clone github 上的 demo,也可以直接下载安装 Demo APK。
推荐阅读: