Monday, November 21, 2011

Places Demo Part V: Location Animation

Simple animations to provide a sense of place/navigation are what makes an application shine. They attract the attention of the user to the ongoing operation within the application while providing a sense of continuity, in that sense they are not "fluff" and should be taken very seriously.
One of the nicest things in the places demo is the animation on the map bellow which you should be able to see in the video above. When selecting a city within the demo we can see an animation of the map highlight moving to a new location. To do that we need to start with the map location image here (I set the text background to red to make the white image visible):

We can add this image by using the add multi-image dialog as such:

And now we need to go back to the GUI builder to place the image on the map, don't worry about the location we will get to that soon enough. I select the Map Label entry and change its name to Map (to make it easier to work with it in code), I also change the name of the List at the bottom to cityList.
Next drag a container into the same container where the Map is currently at and set its layout to layered layout. Make sure that the Map entry is before the Container entry which you just added (you can rearrange them in the tree). Drag the Map into that container and place another new container next to it. Drag a label into the new container and call it "MapHighlight", set its text to an empty string, set its UIID to container and select the mapPosition.png image as its icon. You should end up with something that looks like this:

Now its FINALLY time to start writing some code... Click the menu Application->Generate Netbeans Project. Type the name "LWUITPlaces" and select a directory into which the project should be generated. 
Important: you do this only ONCE after that saving the file will automatically update the generated code for you. Also important: If you saved the file in the past the old location is no longer relevant! The resource file will now be within the src directory of the generated project and can't be moved from that location.

In the GUI select the Form and select the events tab in the properties on the right, click the "Before Show" button. This should open the StateMachine.java file in Netbeans and create a method like this:
    protected void beforeMain(Form f) {
        // If the resource file changes the names of components this call will break notifying you that you should fix the code
        super.beforeMain(f);
       
    }

Before we continue go to the top of the class and add the following variables and constants:
    private static final int MAP_ORIGINAL_WIDTH = 178;
    private static final int MAP_ORIGINAL_HEIGHT = 114;
    private int mapActualWidth;
    private int mapActualHeight;
    private static final int [][] MAP_POINTS =  {
        {10, 65},
        {0, 42},
        {77, 75},
        {146, 37},
        {107, 33}
    };
   
    private int mapSelection = 0;

We will also need these methods to exist:
    private int mapXCoordinate(int c) {
        return (int)(((float)c) / ((float)MAP_ORIGINAL_WIDTH) * ((float)mapActualWidth));
    }

    private int mapYCoordinate(int c) {
        return (int)(((float)c) / ((float)MAP_ORIGINAL_HEIGHT) * ((float)mapActualHeight));
    }

Some of these things might seem obvious but others might not. When we animate to a particular list offset we need to know the pixel coordinate of the city within the Map. This worked great in Martin & Chen's demo since they used a regular image as the map. The problem is that a regular sized image would not work for lower/higher resolution devices which is why I used a multi-image.
Once I used a multi-image the resolution of the image (hence the coordinates) would change depending on the device, so all the old city coordinates from Martin will no longr work (these are the MAP_POINTS coordinates).

The trick is simple, I ask the size of the map image in runtime and store it within the mapActualWidth/Height variables. Then I calculate the position in map offsets using a simple ratio equasion in the mapXCoordinate/mapYCoordinate methods.


Back to the beforeMain method (under the super call) we will write the code to position the selection based on coordinates. With the comments within the body I hope the content of this method is clear enough:


3 comments:

  1. Hi. I tried to follow the example but all the buttons on the event tab seem to be disabled.
    Is there a known issue with the webstart version?

    I hope you can answer soon.
    Best regards and keep the great job.

    ReplyDelete
  2. After you generate the netbeans project they become enabled. From this point on you need to start working with the resource file that is within the generated project.

    ReplyDelete
  3. Thanks. I'll see how that goes.
    Best regards.

    ReplyDelete