Software Development

Code challenge: Use Android's updated animation APIs for a chance to win swag

We'll send TechRepublic swag to the reader who submits the most elegant refactoring of this Android sample. Get the details.

Since it's unveiling in 2007, Android has come a long way. It takes only a quick glance at a few screenshots of Donut (Figure A) and KitKat (Figure B) to see what I mean. 

Figure A

here_or_there_01_112013.png
  Figure B

here_or_there_02_112013.png
   

If, like me, you've been along for the ride, you probably have apps either in the Market or more likely retired that could benefit from some of the new APIs available. Thus, when my editor here at TechRepublic suggested I post a code challenge for readers, I decided it would make sense to dust off an old code example I had laying around to collaborate with readers to streamline it using some of the handy animation APIs introduced beginning with Honeycomb.

Below I have a code sample I decided to call "Here or There." In theory, it is very straightforward. Press the Here button, and the red rectangle slides to the left; press the There button, and it slides to the right. At the time I wrote the sample, Android 1.6 was what I had to work with. While the animation was not terribly difficult, it was a struggle to update the subsequent layout. I basically had to reset the layout parameters for the view I was animating following the animation and then force the layout to render again. Not only is it a clunky solution, but it has an annoying flicker.


When I look at the code now I cringe, and you're probably doing the same. That's okay -- in fact, it's the idea. In a subsequent post, I will share how to tackle this animation using the updated Android SDK. Seeing the streamlined version of the code next to the original will really hammer home just how much easier Android development has become.

Oh, and did I mention that we'll send TechRepublic swag to the reader who submits the most elegant refactoring of the code between now and then? No? Well, we will. So, take a few minutes to update the sample (please target Android 3.0 or better), zip it up, and send it my way at the email address mary dot weilage at cbs dot com by December 6, 2013. Even if you're not an Android developer but you're thinking about becoming one, you should take a stab at this code challenge. If you don't have experience with the animation framework, googling Honeycomb's object animator and the subsequent view property animator is a good place to start.

activity_main.xml
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"        
    android:layout_height="fill_parent"
    android:orientation="horizontal">
        
        <Button 
            android:layout_marginLeft="20dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="HERE"
            android:layout_alignParentLeft="true"
            android:layout_centerInParent="true"
            android:id="@+id/here_button"/>
        
        <View 
            android:layout_width="20dp"
            android:layout_height="20dp"
            android:padding="10dp"
            android:background="#ffff0000"
            android:id="@+id/cursor"
            android:layout_toRightOf="@+id/here_button"
            android:layout_centerVertical="true"/>
        
        <Button 
            android:layout_marginRight="20dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="THERE"
            android:id="@+id/there_button"
            android:layout_alignParentRight="true"
            android:layout_centerInParent="true"/>
        
</RelativeLayout>
MainActivity.java
package com.authorwjf.hereorthere;

import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
import android.view.animation.TranslateAnimation;
import android.widget.RelativeLayout;
import android.app.Activity;

public class MainActivity extends Activity implements OnClickListener, AnimationListener {

	private final static int HERE = -1;
	private final static int THERE = 1;
	private TranslateAnimation anim;
	private View cursor;
	private int screenWidth;
	private int centerOfScreen;
	private int dest;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		screenWidth = (int) (getWindowManager().getDefaultDisplay().getWidth());
		centerOfScreen = (int) (screenWidth *.5);
		cursor = findViewById(R.id.cursor);
		findViewById(R.id.here_button).setOnClickListener(this);
		findViewById(R.id.there_button).setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		if (v.getId()==R.id.here_button) {
			animate(HERE);
		} else {
			animate(THERE);
		}
	}
	
	private void animate(int whichWay) {
		if (anim!=null && !anim.hasEnded()) return;
		float target;
		int currentX = cursor.getLeft();
		if (whichWay==HERE ) {
			if (currentX+cursor.getWidth()<=centerOfScreen) return;
			target = (currentX - 
					(findViewById(R.id.here_button).getLeft() + findViewById(R.id.here_button).getWidth()))*-1;
		} else {
			if (currentX>centerOfScreen) return;
			target = findViewById(R.id.there_button).getLeft() - (currentX + cursor.getWidth());
		}
		anim = new TranslateAnimation( TranslateAnimation.ABSOLUTE,0,
			      TranslateAnimation.ABSOLUTE,target,
			      TranslateAnimation.ABSOLUTE,0.0f,
			      TranslateAnimation.ABSOLUTE,0.0f);
		anim.setDuration(500);
		dest = (int) target+cursor.getLeft()+cursor.getWidth();
        anim.setAnimationListener(this);
        cursor.startAnimation(anim);
	}

	@Override
	public void onAnimationEnd(Animation arg0) {
		RelativeLayout.LayoutParams params = 
				new RelativeLayout.LayoutParams(cursor.getWidth(), cursor.getHeight());
		if (dest >= centerOfScreen) {
			params.addRule(RelativeLayout.LEFT_OF, R.id.there_button);
		} else {
			params.addRule(RelativeLayout.RIGHT_OF, R.id.here_button);
		}
		params.addRule(RelativeLayout.CENTER_VERTICAL);
		cursor.setLayoutParams(params);
	}

	@Override
	public void onAnimationRepeat(Animation arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onAnimationStart(Animation arg0) {
		// TODO Auto-generated method stub
		
	}
	
}
For those who prefer, you can download and import the entire project directly into Eclipse.

Don't forget: get your refactored version of this code to us by November 30th to be eligible for the prize and a shout out in an upcoming article.

I look forward to reading your submissions!

About

William J Francis began programming computers at age eleven. Specializing in embedded and mobile platforms, he has more than 20 years of professional software engineering under his belt, including a four year stint in the US Army's Military Intellige...

5 comments
abel_mdo
abel_mdo

Please, anyone let me know the email address to submit the refactored version of the program...

RMSx32767
RMSx32767

Huh, and I thought swag is an acronym for Scientific Wild Ass Guess.

SnoopDougEDoug
SnoopDougEDoug

I think your email address should have two 'l's, LOL.

authorwjf
authorwjf

@abel_mdo

The email address for your submission is: trol@techrepublic.com  

Look forward to seeing it

MaryWeilage
MaryWeilage moderator

@authorwjf @abel_mdo I'm sorry to report that we're experiencing problems receiving emails to the email address we originally provided for this challenge. We have extended the deadline to this Friday and changed the email for submissions to my email address.

My sincere apologies for these technical difficulties.