Archive

Tag Archives: support library

The unveiling of Android 4.3 was followed by the arrival of a new Support Library (revision 18). Besides adding new features to the v4 library, Google introduced a new compatibility element in v7, which aims to bring the ActionBar UI pattern to pre-Honeycomb platforms. Requires API level 7, aka Android 2.1 / Eclair.

By the way, there was already an existing solution for this case: Jake Warton’s ActionBarSherlock is widely used in apps, provides excellent features and easy usability; it might be a good idea to check it out if you’re not already familiar with it.

Usage is pretty easy (and a bit similar to ActionBarSherlock). The first step of course is importing the library (in Eclipse: as library project, in Android Studio / IntelliJ: both as module and jar dependency). Adding an ActionBar requires three steps per activity:

  • Extending your activity from the ActionBarActivity class
  • Setting activity theme to a supported theme like Theme.AppCompat, Theme.AppCompat.Light or Theme.AppCompat.Light.DarkActionbar (these can be found here)
  • Adding items in the onCreateOptionsMenu() method, supplied with a specific namespace

Sidenote: the ActionBarActivity is a FragmentActivity subclass, meaning it supports fragments on platforms prior Honeycomb, so you won’t lose fragment compatibility.

A short example, with a menu resource file called menu.xml:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // inflate the layout, etc...
        getSupportActionBar().setTitle("test");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }
}

You can access the ActionBar with the getSupportActionBar() method (instead of the getActionBar(), available in the Activity class from Android 3.0). Many customizing features are available, including split actionbars, actionitems, using a custom view/theme, navigating up with the app icon, using the ShareActionProvider etc. The official ActionBar guide was updated with support package specific content, you can find more info on the subject here.

Declaring the items is almost the same as using the regular ActionBar: by creating a menu resource and using a custom namespace prefix at every actionbar-related attribute. An example:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:yourapp="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/menu_item_1"
          yourapp:showAsAction="always"
          android:icon="@drawable/ic_launcher"
          android:title="@string/menu_item_1" />
</menu>

Here are a couple of screehnshots using the ActionBarActivity on a device running Android 2.2 with different themes: Theme.AppCompat.Light and Theme.AppCompat.Light.DarkActionBar.

SupportActionBar with Theme.AppCompat.Light and Theme.AppCompat.Light.DarkActionBar

SupportActionBar with Theme.AppCompat.Light and Theme.AppCompat.Light.DarkActionBar

The ViewPager is a great UI element which provides a smooth swipe animation for switching between pages. But what if a different scrolling effect is required? Fear not, the support library provides a useful solution called the PagerTransformer. It was introduced in revision 11, and is supported from API level 11 (Honeycomb) or greater.

Usage is pretty straightforward, just attach a PageTransformer to the ViewPager:

viewpager.setPageTransformer(false, new ViewPager.PageTransformer() {
    @Override
    public void transformPage(View page, float position) {
        // do transformation here
        }
});

The transformPage() method has a View and a position parameter. The former represents the current view or fragment, while the latter contains its position. Scrolling events are triggered by both the starting page and the target page, the corresponding transformPage() calls occur simultaneously. A value of zero means the current page is in the center, 1 means a full page offset to the right side, -1 means a full page offset to the left side. Quoted from the developer site:

The position parameter indicates where a given page is located relative to the center of the screen. It is a dynamic property that changes as the user scrolls through the pages. When a page fills the screen, its position value is 0. When a page is drawn just off the right side of the screen, its position value is 1. If the user scrolls halfway between pages one and two, page one has a position of -0.5 and page two has a position of 0.5.

It is a good idea to normalize the position, so you don’t have to bother with the numbers being negative or positive. It’s pretty easy, just do this in every call:

final float normalizedposition = Math.abs(Math.abs(position) - 1);

Now you have a variable that goes from 0 to 1 (and the other way, respectively) if the user scrolls the ViewPager. What you do with it is up to your imagination; here are some basic examples. First, we’ll fade the pages in and out:

@Override
public void transformPage(View page, float position) {
    final float normalizedposition = Math.abs(Math.abs(position) - 1);
    page.setAlpha(normalizedposition);
}

alpha

These lines perform a scaling effect from and to 50%:

@Override
public void transformPage(View page, float position) {
final float normalizedposition = Math.abs(Math.abs(position) - 1);
    page.setScaleX(normalizedposition / 2 + 0.5f);
    page.setScaleY(normalizedposition / 2 + 0.5f);
}

scale

The last example rotates the pages around their Z axis by 30 degrees; you don’t need to normalize for this one. The effect is similar to the cover flow UI pattern:

@Override
public void transformPage(View page, float position) {
    page.setRotationY(position * -30);
}

cover_flow

Of course rotating the views or fragments around the axes is also possible, but the effect might be a bit overwhelming for the user, so I don’t recommend it. Anyway, it can be done with the other setRotation() methods.

These are just some basic examples, you can do much neater stuff with the PagerTransformer. See this link at the official dev site for two good looking effects. You can also combine it with a PagerTitleStrip or a PagerTabStrip.

The ViewPager is one of the best and most versatile part of the Android UI, it enables the developer/designer to show more content on a small screen than possible. The user can swipe between pages, but it is important that the app shows some hints for a proper user experience. Can I swipe some more or is it the last page? What awaits on the previous and next pages?

The support library has two built-in solutions for this situation by providing a View which shows the title of the current page while the previous and next titles are visible on the sides. The PagerTitleStrip was introduced in revision 6 (december 2011), followed briefly by the PagerTabStrip, which was added in revision 9 (june 2012). The latter is a far more powerful tool then the former: it’s interactive (if you click the titles, the pager will set scroll to the proper item accordingly) and has more options to customize appearance. So I recommend the PagerTabStrip, but to be fair, this post will show how to use both.

Read More

The DrawerLayout was introduced in the latest support library (revision 13), and has many similarities with the SlidingPaneLayout (covered in this example). It is used to add navigation capabilities and to display more information in the same activity, with just a swipe from the sides – a great way to add extra functionality without stuffing the screen with controls. Just tell the user the panels are there, otherwise no one will know about them.

The first question is which side should you use in your application? Position the DrawerLayout on the left (start) of the screen if it contains navigation actions. If this is the case, you might want to check out Google’s official NavigationDrawer tutorial. If the DrawerLayout contains actions specific to the current content, it should go on the right (end) side. For example if you create an app for playing music videos, you could put artist infos or playback options into the DrawerLayout. The good news is, you can use both sides in one DrawerLayout.

There are no options for putting a DrawerLayout to the two other sides, and there are good reasons for that. The top area is reserved for the dropdown status bar, a DrawerLayout here would confuse the user, not to mention it will be hard to use if the app isn’t fullscreen. The bottom part is for Now (if you have a phone with on-screen navigation buttons, like a Nexus 4): a swype gesture brings up Google’s search service.

So I’ll start the example with adding three panels to a DrawerLayout. The first is always the main content, it has a width and height of the parent (aka match_parent). I added a View to the left and a fragment to the right, just to demonstrate that DrawerLayout works seamlessly with fragments. The first has a cyan background color, the latter is blue, and the main content is green.

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:id="@+id/dl_main"
    android:layout_height="match_parent" >

    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/fl_main"
        android:background="#00ff00" />

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="end"
        android:background="#0000ff" />

    <fragment
        android:id="@+id/f_main_left"
        android:name="howrobotswork.example.fragment.MockFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="start" />

</android.support.v4.widget.DrawerLayout>

And that’s all, the DrawerLayout is fully functional: swipe from the left for the fragment, from the right for the view. Of course if you want to get serious with some fancy effects, you’ll have to get your hands dirty (with a few extra lines of code, that is). Some ideas for customization:

  • Listen for open and close events via a DrawerListener. Just override the required methods and implement your stuff.
  • If you want to open/close the drawers with a click of a button instead of a swipe, you can find everything you need here.
  • use the setDrawerLockMode() method to enable or disable interaction with a drawer
  • You can change the scrim color, which overlays the main content while a drawer is open. Just use the setScrimColor() method.
  • You can also change the shadow of the drawers with the setDrawerShadow() method. This requires a drawable resource (either from the /res folder or from code, just make sure it has a non-zero width). This can be done both for the left and right drawers, set the gravity parameter acordingly.
DrawerLayout custom shadow and scrim example

DrawerLayout custom shadow and scrim example

If you see stuttering and glitches, you might want to consider Google’s advice, cited from the official documentation:

Avoid performing expensive operations such as layout during animation as it can cause stuttering; try to perform expensive operations during the STATE_IDLE state.