Thursday, September 6, 2012

Google Now Cards Layout

If you are a fan of Google's android applications, you must haven't missed cards animation that Google Now brings in on Android 4.1, Jelly Bean.

Google Now Cards Layout on Jellybean

Lets see how to create these smooth animations.

You can browse the source here : https://github.com/shardul/Android/tree/master/NowLayout

Step 1 : Animations and Styles

There are two animations of similar sliding transition, differing slightly for alternating cards (technically Views). One rotating in from left and other for right. 

slide_up_left.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="@integer/config_slide_time"
        android:fromYDelta="100%p"
        android:toYDelta="0" />

    <alpha
        android:duration="@integer/config_slide_time"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <rotate
        android:duration="@integer/config_slide_time"
        android:fromDegrees="25"
        android:pivotX="0"
        android:pivotY="0"
        android:toDegrees="0" />

</set>

slide_up_right.xml


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/accelerate_interpolator" >

    <translate
        android:duration="@integer/config_slide_time"
        android:fromYDelta="100%p"
        android:toYDelta="0" />

    <alpha
        android:duration="@integer/config_slide_time"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

    <rotate
        android:duration="@integer/config_slide_time"
        android:fromDegrees="-25"
        android:pivotX="100%"
        android:pivotY="0"
        android:toDegrees="0" />

</set>

These animations will create alternate card animations.

NowLayout.java


package com.shardul.nowlayout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.AnimationUtils;
import android.widget.LinearLayout;

public class NowLayout extends LinearLayout implements OnGlobalLayoutListener {

 public NowLayout(Context context, AttributeSet attrs) {
  super(context, attrs);
  initLayoutObserver();

 }

 public NowLayout(Context context) {
  super(context);
  initLayoutObserver();
 }

 private void initLayoutObserver() {
        // force vertical orientation and add observer
                setOrientation(LinearLayout.VERTICAL);
  getViewTreeObserver().addOnGlobalLayoutListener(this);
 }

 @Override
 public void onGlobalLayout() {
  getViewTreeObserver().removeGlobalOnLayoutListener(this);

  final int heightPx =getContext().getResources().
                getDisplayMetrics().heightPixels;

  boolean inversed = false;
  final int childCount = getChildCount();

 for (int i = 0; i < childCount; i++) {
  View child = getChildAt(i);

  int[] location = new int[2];

  child.getLocationOnScreen(location);

  if (location[1] > heightPx) {
   break;
  }

  if (!inversed) {
   child.startAnimation(
                        AnimationUtils.loadAnimation(getContext(),
      R.anim.slide_up_left));
   } else {
   child.startAnimation(
                        AnimationUtils.loadAnimation(getContext(),
      R.anim.slide_up_right));
   }

   inversed = !inversed;
  }

 }

}


This is where all the magic will happen. To create alternating animations we can definitely grab each child and start respective animation in activity but a better approach would be to create custom layout and handle animation there which is a better approach to take.

Integrating 


Now we have to make use of NowLayout in our activity.

main.xml


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fillViewport="true" >

    <com.shardul.nowlayout.NowLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#e3e3e3"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />

        <TextView
            android:id="@+id/txtView"
            style="@style/nowCardStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/hello_world"
            tools:context=".MainActivity" />
    </com.shardul.nowlayout.NowLayout>

</ScrollView>

MainActivity.java


package com.shardul.nowlayout;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 }

}

And there you have it. Run the app and see sliding cards similar to Google Now app.

Make sure you share with your friends if you like what you created.

You can also learn about Creating Chrome Style Help Popups on Android.

16 comments:

  1. Hi Shardul,
    nice tutorial! I tried it on my Nexus S 4.1.2 and no animation has been shown, maybe I'm doing something wrong, could you please help me? Moreover could be great if you give me some hint regarding how to overlap the "cards" (check this pic: http://www2.pcmag.com/media/images/351362-jelly-bean-google-now.jpg).
    Thank you
    Pierluigi

    ReplyDelete
    Replies
    1. Hi Piero,

      I wasn't able to load the image. Can you post some code ?

      You can verify differences with your code from here :

      https://github.com/shardul/Android/tree/master/NowLayout

      Thanks,

      Delete
    2. I downloaded the code from github, but when it run on my device no animation are shown. There is just a scroll view with some TextView, when I slide on the TextView any animation is shown... I was expecting the effect the you have when you make a card disappear in Google Now swiping on the left or on the right, am I wrong?

      About the "Overlapping Cards" try this link: http://images.fastcompany.com/upload/google-now-pics-screens.jpg

      Delete
  2. Thanks Shardul. Was looking for this :)

    ReplyDelete
  3. Hi Shardul,

    very nice tutorial, searched a long to find something like that.
    Worked fine, but I've got a question.
    Do you know how I can use a table- or gridlayout in one card instead of the textview?
    Every time I try another layout no card shows up.

    Thanks Jakob

    ReplyDelete
    Replies
    1. Whats the issue there ? It could be any view.

      Delete
  4. Absolutely amazing. Exactly what I was looking for and turned out to be very simple. Thank you for posting this.

    ReplyDelete
  5. Great tutorial!

    Is it possible to try this in flex builder? I am trying to achieve something similar.
    Thanks!

    ReplyDelete
    Replies
    1. No idea about flex implementation. You can Google it out for animations.

      Delete
  6. Great tutorial Shardul. BTW, is there any way to replicate the cards UI of Google+ along with the transition animations of cards?

    ReplyDelete
    Replies
    1. Sure you can :) it has Z axis rotation. In pre 3.0 use camera class to achieve it. Post 3.0 theres ready to use rotation()

      Delete
  7. Awesome tut. Is there a way to set delay time between the sliding in animation from top to bottom though?

    ReplyDelete
  8. Thanks Shardul for your time and effort in making this. I'm a newbie to android and i really appreciate your work :)
    Cheers!

    ReplyDelete
  9. Thanks a lot for this! I was looking for this for my app and nadavfima's CardsUI didn't cut it since it lacks the awesome animations and I don't need the stacking. This is exactly what I need - pure and simple. Excellent work! :)

    ReplyDelete