Home

Awesome

Android Arsenal

Paginize

Scan the QRCode to install the demo APK and get a feel of how it works!

PaginizeDemo

PaginizeDemo

Description

Paginize is a light-weight application framework for Android. It was designed to accelerate development cycles and make maintenance easier, it provides an intuitive programming model for writing Android applications. Paginize models a screen as a Page or part of the screen as an InnerPage, which in essence are just view wrappers. Paginize breaks down complex user interfaces into smaller units, provides APIs for easily handling page navigations, and offers flexibility for page inheritance and layout inheritance, which pushes code reuse in Android to another level.

Installation

compile 'net.neevek.android:paginize:0.6.13'

To to make your life easier, some useful implementations(BasePageOptionMenuPage, etc.) are provided, include the following dependency to use it. The following dependency is not required to use Paginize itself. See the demo for details.

compile 'net.neevek.android:paginize-contrib:0.0.1'

Documentation

  1. Getting started
  2. The lifecycle callbacks
  3. Paginize annotations
  4. Argument passing between pages
  5. Proguard rules

####<a name="header1"></a> 1. Getting started

  1. Create a layout file(res/layout/page_frame.xml) for FramePage:
<!-- for brevity, referenced resources are not shown here. see the demo-->
<?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"
    />

  <ViewStub
    android:id="@+id/stub_loading_layout"
    android:layout="@layout/layout_loading"
    android:inflatedId="@+id/layout_loading"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="?attr/actionBarSize"
    />

  <ViewStub
    android:id="@+id/stub_error_layout"
    android:layout="@layout/layout_error"
    android:inflatedId="@+id/layout_error"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="?attr/actionBarSize"
    />
</android.support.design.widget.CoordinatorLayout>
  1. Create FramePage, this page will be inherited by other pages that need a ToolBar
@PageLayout(R.layout.page_frame)
public abstract class FramePage extends Page {
  @InjectView(R.id.tb_header_bar)
  private Toolbar mTbToolbar;

  public FramePage(PageActivity pageActivity) {
    super(pageActivity);

    if (getContext().getPageCount() > 0) {
      ToolbarHelper.setNavigationIconEnabled(mTbToolbar, true, new View.OnClickListener() {
        @Override
        public void onClick(View v) {
          onNavigationIconClicked(v);
        }
      });
    }
  }

  protected final void setupMenu(@MenuRes int menuResId) {
    ToolbarHelper.setupMenu(mTbToolbar, menuResId, new Toolbar.OnMenuItemClickListener() {
      @Override
      public boolean onMenuItemClick(MenuItem item) {
        return FramePage.this.onMenuItemClick(item);
      }
    });
  }

  protected void onNavigationIconClicked(View v) {
    hide(true);
  }

  protected boolean onMenuItemClick(MenuItem item) {
    return false;
  }

  protected final Toolbar getToolbar() {
    return mTbToolbar;
  }
}

  1. Create another layout(page_test.xml) for TestPage, this page contains only a TextView:
<TextView
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/tv_content"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:gravity="center"
  android:padding="10dip"
  />
  1. Create TestPage:
// here we inherit the layout from FramePage, i.e. R.layout.page_frame,
// insert R.layout.page_test into the R.id.container element of the parent
// layout. Since we subclass FramePage, we also inherit the code for handling
// the BACK button press
@InsertPageLayout(value = R.layout.page_test, parent = R.id.layout_content_container)
public class TestPage extends FramePage {
    @InjectView(R.id.tv_content)
    private TextView mTvContent;

    public TestPage(PageActivity pageActivity) {
      super(pageActivity);
      mTvContent.setText("Hello Paginize!");
    }
}

After the steps above, TestPage is a page that contains a ToolBar. As you can see, we don't need to repeat the boilerplate code for setting up the views of FramePage. Page inherited, its layout is inherited as well.

  1. Create an Activity that extends PageActivity, and show the TestPage:
@InjectPageAnimator(SlidePageAnimator.class)
public class MainActivity extends PageActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // pass true to animate the transition
        new TestPage(this).show(true);
    }
}

That's all for using Paginize to make a one screen application. Here you may find that it is sort of more hassle than just use Activity, but Paginize is extremely useful when you use it to make more complicated applications, you see the advantages of it when you use it to structure a real application.

####<a name="header2"></a> 2. The lifecycle methods

Page (including Page and InnerPage) subclasses ViewWrapper, lifecycle methods are declared in this class:

When a page is popped, it is ready be to garbage collected, because for most cases no one references the page at this point, but you could, that means if you keep a reference to the page, you can call show()/hide() pair multiple times to reuse the page. And that is why the method is named onHidden() instead of onDestroy(), because the framework will not know whether it is destroyed.

Besides the lifecycle methods introduced by the framework, Paginize mirrors most of the Activity lifecycle methods, for example, when onResume() is called for the current Activity, Paginize passes the method call to the top page(the currently showing page), same for methods like onPause(), onActivityResult(), etc.

####<a name="header3"></a> 3. Paginize annotations

Paginize takes advantage of Java Annotations to make use of the framework easier, and make features like layout inheritance possible. Some of the annotations are just syntax sugar to make the code more consistent when using Paginize.

####<a name="header4"></a> 4. Argument passing between pages

For passing arguments to a newly created page, use getBundle, and set arguments in the returned bundle. Paginize will save the bundle associated with each Page during onSaveInstanceState, and restore it during onRestoreInstanceState, which means no extra work needed for saving and restoring arguments during page recreation, the bundle will be ready in onShow and lifecycle methods after that. For navigating back from a page, onUncover() and onUncovered() can be used to receive arguments from the popped page, these two methods take an object as argument, which is passed from the top page set with setReturnData() before it is popped from the page stack.

####<a name="header5"></a> 5. Proguard rules

To prevent annotated classes and fields from being stripped away, the following rules must be put in proguard-project.txt.

-keep public class net.neevek.android.lib.paginize.**
-keep @net.neevek.android.lib.paginize.annotation.ListenerMarker class ** { *; }
-keepclassmembers,allowobfuscation class ** {
  @net.neevek.android.lib.paginize.annotation.** <fields>;
}

Note

The project is still NOT stable, APIs may change(but not significantly).

For more, check out the demo project.

Contributing

Please fork this repository and contribute back using pull requests.

Under MIT license

Copyright (c) 2014 neevek <i@neevek.net>
See the file license.txt for copying permission.