ViewPager with FragmentPagerAdapter

Spend one hour trying find how to access my list fragment as there was no explicit fragment ID

1. Get current select view page

ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
int id = viewPager.getCurrentItem();

2. Get Fragment by tag

Fragment frag = getFragmentManager().findFragmentByTag(“android:switcher:”+R.id.pager+”:”+id);

Then you can access your fragment reference.

convertView in Android listview

I am sure you must have come face to face with one of Android’s most common composite view – the ListView. And also at some point or the other, you must have felt the need to populate your List with some custom views using your own adapter which must have extended the BaseAdapter , instead of simply using a ListAdapter .

All’s fine till this point, you merrily extend your adapter with the BaseAdapter, implement the unimplemented methods necessary until you see the getView( ) method with three parameters if I remember correctly.

1
2
3
4
public View getView(int position, View convertView, ViewGroup parent) {
        //What-to-do here
        return null;
    }

Yep, it is three alright. You can comprehend what position is. Parent is the ListView being populated, obviously. But what in the green droid is convertView? Well, it is the single child element of the ListView that android is going to use to inflate your custom view layout (ya, the one you defined in xml… if you have note done that yet, better do it now!).

Now a word on how it all works – the concept behind convertView. You see, your ListView,which you are going to populate with your custom elements, needs to know how many of them will fit the device screen at a given time. This is the job for Android to carry out. According to the parameters like height, width of the element, which you have (I hope) defined in the xml file for that custom view, and the screen metrics (height and width of the screen), Android will calculate how many of the elements can fill into the screen at one time. Say, that number is 7. This means, when your list view is first initialized, 7 items (even the partially displayed ones count) are displayed, with 7 calls going to the getView method in your adapter.During these first 7 calls, the convertView parameter is null, since there is no existing container to inflate your views in. Hence you must inflate your views for the first time in the

1
2
3
if(convertView == null){
     //Inflate Views here from xml and no other task
}

block.

Now, what happens as you scroll from the 7th element to the 8th. Obviously, your screen can only display 7 elements at a time (as assumed earlier) so the 1st element will go out of view once the 8th element is brought up. Again a call to getView() will be made, but the difference this time is that convertView will not be null. Android would recycle the container used to inflate the first element since the first element is no longer required in memory. When the list is scrolled up again to the first element, again a getView call, but this time convertView won’t be null, as the 8th element’s container will be used. This cycle and re-cycle of containers is repeated as we scroll up and down the list with subsequent calls to getView().

Hence, one must be careful to assign values to different variables inside the custom element/view, outside the block where we check convertView to be null, as otherwise, all elements after the 7th element as in our case, shall start repeating !

A Simple List View with custom elements

There you have it… convertView : Decoded 🙂

Holo Action Bar and Layout preview in Android studio

Preview in Android studio

Android studio layout preview function makes life so easy, you can choose your theme, API level to preview. So it’s very easy to simultaneously develop themes under different APIs. At the moment, I am developing two themes. One is for API 21 Lollipop and API 15 for IceCreamSandwich. API 15 will cover 90.4% of devices that are active on Google Play store.

Holo Action Bar

Background:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- the theme applied to the application or activity -->
    <style name="CustomActionBarTheme"
           parent="@android:style/Theme.Holo.Light.DarkActionBar">
        <item name="android:actionBarStyle">@style/MyActionBar</item>
    </style>

    <!-- ActionBar styles -->
    <style name="MyActionBar"
           parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
        <item name="android:background">@drawable/actionbar_background</item>
    </style>
</resources>

Best practice for instantiating a new Android Fragment

If Android decides to recreate your Fragment later, it’s going to call the no-argument constructor of your fragment. So overloading the constructor is not a solution.

With that being said, the way to pass stuff to your Fragment so that they are available after a Fragment is recreated by Android is to pass a bundle to the setArguments method.

So, for example, if we wanted to pass an integer to the fragment we would use something like:

public static MyFragment newInstance(int someInt) {
    MyFragment myFragment = new MyFragment();

    Bundle args = new Bundle();
    args.putInt("someInt", someInt);
    myFragment.setArguments(args);

    return myFragment;
}

And later in the Fragment you can access that integer by using:

getArguments().getInt("someInt", 0);

This Bundle will be available even if the Fragment is somehow recreated by Android.

Also note: setArguments can only be called before the Fragment is attached to the Activity.

Android Studio Rename Package

In Android Studio, you can do this:

For example, if you want to change com.example.app to my.awesome.game, then:

  1. In your Project pane, click on the little gear icon ( Gears icon )
  2. Uncheck / De-select the Compact Empty Middle Packages option

Compact Empty Middle Packages

  1. Your package directory will now be broken up in individual directories
  2. Individually select each directory you want to rename, and:
    • Right-click it
    • Select Refactor
    • Click on Rename
    • In the Pop-up dialog, click on Rename Package instead of Rename Directory
    • Enter the new name and hit Refactor
    • Allow a minute to let Android Studio update all changes
    • Note: When renaming com in Android Studio, it might give a warning. In such case, selectRename All

enter image description here

  1. Now open your Gradle Build File (build.gradle – Usually app or mobile). Update the applicationId to your new Package Name and Sync Gradle, if it hasn’t already been updated automatically:

Refactor Directories

  1. Done! Anyways, Android Studio needs to make this process a little simpler.

Floating Action Buttons in Android Lollipop

At 2014 Google I/O, Google announced a new visual language called Material Design. Material Design guides creation of user experiences that work well on different devices, with different input methods and on different platforms. Google is gradually implementing Material Design in their apps and products, and we can start playing with it, too.

One interesting new design pattern is the promoted action, implemented as a floating action button. This pattern exemplifies the underlying principles of Material Design and is a good place to start adapting existing applications to the new version of Android.

You can see from Google’s guidelines that there are many ways to apply this pattern incorrectly, as evidenced by the various “Don’ts” on that page. Today, I want to show you how to implement a floating action button without creating a “Don’t” yourself.

Float Like a Button, Sting Like an Action

If you are just as excited as I am to get my hands dirty and create clean user interfaces with Google’s Material Design, you have probably already downloaded Android Studio 1.0 and Android Lollipop emulator images. If not, go ahead and do so now.

Our Criminal Intent project is a perfect fit for this tutorial. If you haven’t done so, grab your copy ofAndroid Programming: The Big Nerd Ranch Guide and work through Chapters 7-22. (If you’ve done this a long time ago and can’t locate your code, you can also get the solutions from our website).

In the Criminal Intent app, the “Add New Crime” button appears in the Action Bar. It’s a good candidate to be the promoted action, so we will update the app for Lollipop. This is what our final result will look like:

Floating action button

Replacing the Menu Item

Before we work on the button, we need to remove the “Add New Crime” menu item, by creating the res/menu-v21/fragment_crime_list.xml file:

    <!-- res/menu-v21/fragment_crime_list.xml -->
    <menu xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:id="@+id/menu_item_show_subtitle"
              android:title="@string/show_subtitle"
              android:showAsAction="never"/>
    </menu>

Now it’s time to add the button. Since CrimeListFragment is a subclass of ListFragment, we didn’t have to define a layout for it. We’ll do this here, by creating fragment_crime_list.xml in layout-v21:

    <!-- res/layout-v21/fragment_crime_list.xml -->
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent">

        <include layout="@android:layout/list_content"/>

        <ImageButton
            android:id="@+id/add_button"
            android:layout_width="@dimen/round_button_diameter"
            android:layout_height="@dimen/round_button_diameter"
            android:layout_gravity="end|bottom"
            android:layout_marginBottom="@dimen/add_button_margin"
            android:layout_marginEnd="@dimen/add_button_margin"
            android:src="@android:drawable/ic_input_add"/>

    </FrameLayout>

We will use this layout for Lollipop and fall back to the super implementation for previous versions (in CrimeListFragment.java):

    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        View v;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            v = inflater.inflate(R.layout.fragment_crime_list, parent, false);
        } else {
            v = super.onCreateView(inflater, parent, savedInstanceState);
        }

At the time of the original post Lollipop hadn’t come out yet. Because Android L was a preview release, things worked a bit differently. Build.VERSION_CODES.L did exist, but its value was set to 10000. The Android L emulator’s Build.VERSION.SDK_INT was 20. Thus we had to use code KITKAT_WATCH, even though it referred to v20 and not v21. Now that Lollipop is out, we don’t have to play with numbers.

Changing the Look and Feel

So far, the button doesn’t look like the floating action button we want. Let’s change the tint and background:

android:tint="@android:color/white"
android:background="@drawable/oval"

Better! But it’s still not floating. For that, we need to change its elevation:

android:elevation="@dimen/elevation_low"

Because the button is still rectangular, the elevated button drops a rectangular shadow. Fortunately, we can change the button’s outline and clip it (in CrimeListFragment.java):

    // CrimeListFragment.java - onCreateView()
    View addButton = v.findViewById(R.id.add_button);
    addButton.setOutlineProvider(new ViewOutlineProvider() {
        @TargetApi(Build.VERSION_CODES.LOLLIPOP)
        @Override
        public void getOutline(View view, Outline outline) {
            int diameter = getResources().getDimensionPixelSize(R.dimen.diameter);
            outline.setOval(0, 0, diameter, diameter);
        }
    });
    addButton.setClipToOutline(true);

In Lollipop, the API changed a bit. Thanks to our commenters for pointing it out. Instead of setOutline, we now use setOutlineProvider.

The evolution of the button:

Button 1Button 2Button 3Button 4

Adding the Ripple Effect and Shadow

We’re almost done! We just need to do two things. First, we need to bring back the ripple effect. Second, we need to change the size of the shadow when the button is pressed.

To re-enable the ripple, we need to change the button’s background from a static shape to a rippleandroid:background="@drawable/oval_ripple" and create the oval_ripple drawable:

    <!-- res/drawable/oval_ripple.xml -->
    <ripple xmlns:android="http://schemas.android.com/apk/res/android"
        android:color="?android:colorControlHighlight">
        <item>
            <shape android:shape="oval">
                <solid android:color="?android:colorAccent"/>
            </shape>
        </item>
    </ripple>

The last effect is to increase the size of the shadow, and we need to lift the button up after we push down on it. To make it happen, add one more property to the button: android:stateListAnimator="@anim/button_elevation" and create the button_elevation animation:

    <!-- res/anim/button_elevation.xml -->
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true">
            <objectAnimator
                android:propertyName="translationZ"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueFrom="@dimen/elevation_low"
                android:valueTo="@dimen/elevation_high"
                android:valueType="floatType"/>
        </item>
        <item>
            <objectAnimator
                android:propertyName="translationZ"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueFrom="@dimen/elevation_high"
                android:valueTo="@dimen/elevation_low"
                android:valueType="floatType"/>
        </item>
    </selector>

These are the values in dimens.xml:

    <!-- res/values/dimens.xml -->
    <dimen name="diameter">48dp</dimen>
    <dimen name="elevation_low">1dp</dimen>
    <dimen name="elevation_high">4dp</dimen>
    <dimen name="add_button_margin">16dp</dimen>

Finally, the button needs to perform the action that used to be accessible via the Action Bar, so we add the OnClickListener:

    addButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            addNewCrime();
        }
    });

Here’s the zoomed in view of the finished result:

Final floating action button

That’s it! With just a handful of new XML files and code, we kicked off the redesign of the Criminal Intent app and implemented a floating action button. There is a lot more to Material Design; read the guidelines, but keep in mind that they’re still being refined.