What you learn: You will learn how to create a Christmas Calendar using a TableLayout and how to start SubActivities (+ passing extra Data to them).
Difficulty: 24 of 31
What it will look like:
[align=center]Running on different Resolutions,
reveals the power of XML-Based GUI-Definition:
[/align]
Description:
The whole setup of this application is pretty simple, as we have just a lot of the same thing to do (like 24 times
0.) The first thing as always we will do is to think about the layout of what we want to display.
As we want to display a calendar, a TableLayout would fit absolutely perfect
Lets take a look at the calendar_layout.xml. It will consist of 4 Rows, with 6 columns each. Each field in our table is 'filled' with a Button, that has a ID, a Text (the day) and as we do not want normal buttons, but fancy look-through ones, we apply a Style to them(which we will also create in the next step).
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <!-- Demonstrates using a TableLayout to create a christmas calendar -->
- <TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:background="@drawable/christmasbackground"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:stretchColumns="0,1,2,3,4,5"
- >
- <TableRow
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <Button id="@+id/cmd_door_2" style="@style/DoorButton" android:text="2"/>
- <Button id="@+id/cmd_door_21" style="@style/DoorButton" android:text="21"/>
- <Button id="@+id/cmd_door_11" style="@style/DoorButton" android:text="11"/>
- <Button id="@+id/cmd_door_10" style="@style/DoorButton" android:text="10"/>
- <Button id="@+id/cmd_door_5" style="@style/DoorButton" android:text="5"/>
- <Button id="@+id/cmd_door_16" style="@style/DoorButton" android:text="16"/>
- </TableRow>
- <TableRow
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
- <Button id="@+id/cmd_door_7" style="@style/DoorButton" android:text="7"/>
- ....
- </TableRow>
- <TableRow ... >
- ....
- </TableRow>
- <TableRow ... >
- ....
- </TableRow>
- </TableLayout>
Parsed in 0.005 seconds, using GeSHi 1.0.8.4
As we want to fill the whole screen(at least in width) we applied above the following code to the TableLayout:
Using xml Syntax Highlighting
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:stretchColumns="0,1,2,3,4,5"
Parsed in 0.000 seconds, using GeSHi 1.0.8.4
1.) As see in the screenshots above we are not handling "standard"-Buttons
Every Button is adapted to the same customized style:
Using xml Syntax Highlighting
- <Button id="@+id/cmd_door_7" style="@style/DoorButton" android:text="7"/>
Parsed in 0.001 seconds, using GeSHi 1.0.8.4
We remember that the "@"-sign refers to a resource of this project, here "@style" refers to a style-resource. Styles like the @style/DoorButton are normally defined within the styles.xml.
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <style name="DoorButton">
- <!-- Replaces the complex BackGround to a simple color -->
- <item name="android:background">@color/door_background</item>
- <!-- Text-Style -->
- <item name="android:textSize">26sp</item>
- <item name="android:textStyle">bold</item>
- <!-- Text-Color -->
- <item name="android:textColor">@color/door_caption_color_selected</item>
- <item name="android:normalTextColor">@color/door_caption_color</item>
- <!-- Spacing between the Buttons -->
- <item name="android:padding">4px</item>
- <item name="android:paddingTop">6px</item>
- </style>
- </resources>
Parsed in 0.003 seconds, using GeSHi 1.0.8.4
So we are simply overriding the default-style-parameters for the Button. We once again refer to xml-Color-Definitions we place in a file like colors.xml.
[align=center]:arrow: Detailed explanation of defining colors in xml[/align]
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <resources>
- <color name="door_background">#4200</color>
- <color name="door_caption_color_selected">#F00</color>
- <color name="door_caption_color">#BBFF0000</color>
- </resources>
Parsed in 0.002 seconds, using GeSHi 1.0.8.4
[align=center]Phew, that was enough XML for [s]this tutorial[/s] now =)[/align]
2.) Lets get to the ChristmasCalendar.xml:
We will need an OnClickListener to react on the clicks to all of the 24 Buttons. We choose one single OnClickListener for all Buttons as a click on them will lead to almost the same outcome just a different picture (/res/drwawable/door_X.gif) will be loaded).
So we read out the Caption of the Button, switch on it, to get the related Drawable-Resource (put that to a b]Bundle[/b](within an b]Intent[/b]), that will be passed to our b]ImageDisplay[/b]-SubActivity, which displays the Drawable.
Using java Syntax Highlighting
- public OnClickListener myOcl = new OnClickListener(){
- // @Override
- public void onClick(View aView) {
- /* It definitely was a button that was
- * clicked, as we assigne only Buttons
- * to this OnClickListener */
- Button clickedButton = (Button)aView;
- String buttonCaption = clickedButton.getText().toString();
- Integer buttonNumber = Integer.parseInt(buttonCaption);
- int drawableResID = 0;
- switch(buttonNumber){
- case 1: drawableResID = R.drawable.door_1; break;
- case 2: drawableResID = R.drawable.door_2; break;
- case 3: drawableResID = R.drawable.door_3; break;
- // ... 4 - 22 here too =)
- case 23: drawableResID = R.drawable.door_23; break;
- case 24: drawableResID = R.drawable.door_24; break;
- }
Parsed in 0.033 seconds, using GeSHi 1.0.8.4
We now determined the Drawable behind this calendar-door. Now we prepare to send an Intent to the ImageDisplayer-Activity (will be explained seperately) the will display that Drawable.
Using java Syntax Highlighting
- /* This Intent will start the Viewing
- * of the image behind the door later */
- Intent i = new Intent(ChristmasCalendar.this,
- ImageDisplayer.class);
- /* We want to send two extra-datasets
- * (the ResID of the Drawable and some text)
- * to our ImageDisplayer */
- // A Bundle is just like a pimped HashMap
- Bundle myExtras = new Bundle(2);
- // Add those to extra datasets
- myExtras.putString(CAPTION_TO_SHOW_MARKER, "Behind door " + buttonCaption + " is...");
- myExtras.putInteger(DRAWABLE_RESID_MARKER, drawableResID);
- /* Assign the Bundle to the Intent.
- * The Intent will 'carry' it to the
- * SubActivity, where we will read the values back */
- i.putExtras(myExtras);
- // We use SUB_ACTIVITY_REQUEST_CODE as an 'identifier'
- startSubActivity(i, IMAGESUBACTIVITY_ID);
- }
- };
Parsed in 0.034 seconds, using GeSHi 1.0.8.4
3.) Lets take a look at the onCreate(...)-method of our ChristmasCalendar-Activity. It also does not much except calling applyListenerToButtons(myOcl);, which applies the listener from the previous step to all the 24 Buttons from our XML-Layout. After that it simply displays a Notification that shows the current Date and Time (don't cheat on opening doors of tomorrow
):
Using java Syntax Highlighting
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.calendar_layout);
- // Apply the Button-Listener to all Buttons from the xml-file
- applyListenerToButtons(myOcl);
- // Retrieve a dateString using the DateUtils
- String dateString = DateUtils.dateString(
- System.currentTimeMillis()).toString();
- // Get the notification manager serivce.
- NotificationManager nm = (NotificationManager)
- getSystemService(NOTIFICATION_SERVICE);
- /* Show a message showing the current date */
- nm.notifyWithText(NOTIFICATION_ID,"Today is: " + dateString + "\n\t\tdon't cheat <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />",
- NotificationManager.LENGTH_LONG, null);
- }
Parsed in 0.037 seconds, using GeSHi 1.0.8.4
A part of the 'monotonous' applyListenerToButtons()-method:
Using java Syntax Highlighting
- private void applyListenerToButtons(OnClickListener aOcl){
- // 1 to 10
- findViewById(R.id.cmd_door_1).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_2).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_3).setOnClickListener(aOcl);
- // ...
- findViewById(R.id.cmd_door_10).setOnClickListener(aOcl);
- // 11 to 20
- findViewById(R.id.cmd_door_11).setOnClickListener(aOcl);
- // ...
- findViewById(R.id.cmd_door_20).setOnClickListener(aOcl);
- // 21 to 24
- findViewById(R.id.cmd_door_21).setOnClickListener(aOcl);
- // ...
- findViewById(R.id.cmd_door_24).setOnClickListener(aOcl);
- }
Parsed in 0.038 seconds, using GeSHi 1.0.8.4
Together with some Constants we are now done with this Activity
Using java Syntax Highlighting
- // Just random unique ints!
- public static final int NOTIFICATION_ID = 0x1337;
- public static final int IMAGESUBACTIVITY_ID = 0x7331;
- public static final String DRAWABLE_RESID_MARKER = "DRAWABLE_RESID_MARKER";
- public static final String CAPTION_TO_SHOW_MARKER = "CAPTION_TO_SHOW_MARKER";
Parsed in 0.036 seconds, using GeSHi 1.0.8.4
4.) The ImageDisplayer.java-Activity is pretty simple. It loads a Drawable using the id that it got passed in the bundle we sent to it on a click to on of the calendar-doors of the Main-Part. Also provides an simple close-button.
[align=center]This is what the ImageDisplayer-Activity will look like:
[/align]
Using java Syntax Highlighting
- package org.anddev.android.christmascalendar;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.ImageView;
- public class ImageDisplayer extends Activity{
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- // Apply our subactivity.xml-Layout
- setContentView(R.layout.imagedisplayer_layout);
- // Read out the passed title and apply it
- String captionToShow = getIntent().getExtras()
- .getString(ChristmasCalendar.CAPTION_TO_SHOW_MARKER);
- this.setTitle(captionToShow);
- // Find the ImageView from our xml-layout
- ImageView iv = (ImageView)findViewById(R.id.image);
- // Read out the drawableResID
- int drawableResID = getIntent().getExtras()
- .getInteger(ChristmasCalendar.DRAWABLE_RESID_MARKER);
- iv.setImageResource(drawableResID); // apply it
- iv.invalidate(); // ensures at least one redraw
- // Find the button defined in the subactivity.xml
- Button cmd_return = (Button)findViewById(R.id.subactivity_cmd_return);
- /* Add an OnClickListener to it, that close this activity */
- cmd_return.setOnClickListener(new OnClickListener(){
- // @Override
- public void onClick(View arg0) {
- // Close this Activity
- ImageDisplayer.this.finish();
- }
- });
- }
- }
Parsed in 0.041 seconds, using GeSHi 1.0.8.4
Finally the xml-Layout for the ImageDisplayer:
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <ImageView id="@+id/image"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- <Button id="@+id/subactivity_cmd_return"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="BACK"
- />
- </LinearLayout>
Parsed in 0.002 seconds, using GeSHi 1.0.8.4
[align=center]:) Thats it
[/align]
The full Source:
'AndroidManifest.xml'
Using xml Syntax Highlighting
- <?xml version="1.0" encoding="utf-8"?>
- <manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="org.anddev.android.christmascalendar">
- <application android:icon="@drawable/icon">
- <activity class=".ChristmasCalendar" android:label="@string/app_name">
- <intent-filter>
- <action android:value="android.intent.action.MAIN" />
- <category android:value="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity class=".ImageDisplayer" android:label="Picture Viewer">
- <intent-filter>
- <action android:value="android.intent.action.VIEW" />
- <category android:value="android.intent.category.DEFAULT" />
- </intent-filter>
- </activity>
- </application>
- </manifest>
Parsed in 0.004 seconds, using GeSHi 1.0.8.4
'src/your_package_structure/ChristmasCalendar.java'
Using java Syntax Highlighting
- package org.anddev.android.christmascalendar;
- import android.app.Activity;
- import android.app.NotificationManager;
- import android.content.Intent;
- import android.os.Bundle;
- import android.util.DateUtils;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- public class ChristmasCalendar extends Activity {
- // Just random unique ints!
- public static final int NOTIFICATION_ID = 0x1337;
- public static final int IMAGESUBACTIVITY_ID = 0x7331;
- public static final String DRAWABLE_RESID_MARKER = "DRAWABLE_RESID_MARKER";
- public static final String CAPTION_TO_SHOW_MARKER = "CAPTION_TO_SHOW_MARKER";
- public OnClickListener myOcl = new OnClickListener(){
- // @Override
- public void onClick(View aView) {
- /* It definitely was a button that was
- * clicked, as we assigne only Buttons
- * to this OnClickListener */
- Button clickedButton = (Button)aView;
- String buttonCaption = clickedButton.getText().toString();
- Integer buttonNumber = Integer.parseInt(buttonCaption);
- int drawableResID = 0;
- switch(buttonNumber){
- case 1: drawableResID = R.drawable.door_1; break;
- case 2: drawableResID = R.drawable.door_2; break;
- case 3: drawableResID = R.drawable.door_3; break;
- case 4: drawableResID = R.drawable.door_4; break;
- case 5: drawableResID = R.drawable.door_5; break;
- case 6: drawableResID = R.drawable.door_6; break;
- case 7: drawableResID = R.drawable.door_7; break;
- case 8: drawableResID = R.drawable.door_8; break;
- case 9: drawableResID = R.drawable.door_9; break;
- case 10: drawableResID = R.drawable.door_10; break;
- case 11: drawableResID = R.drawable.door_11; break;
- case 12: drawableResID = R.drawable.door_12; break;
- case 13: drawableResID = R.drawable.door_13; break;
- case 14: drawableResID = R.drawable.door_14; break;
- case 15: drawableResID = R.drawable.door_15; break;
- case 16: drawableResID = R.drawable.door_16; break;
- case 17: drawableResID = R.drawable.door_17; break;
- case 18: drawableResID = R.drawable.door_18; break;
- case 19: drawableResID = R.drawable.door_19; break;
- case 20: drawableResID = R.drawable.door_20; break;
- case 21: drawableResID = R.drawable.door_21; break;
- case 22: drawableResID = R.drawable.door_22; break;
- case 23: drawableResID = R.drawable.door_23; break;
- case 24: drawableResID = R.drawable.door_24; break;
- }
- /* This Intent will start the Viewing
- * of the image behind the door later */
- Intent i = new Intent(ChristmasCalendar.this,
- ImageDisplayer.class);
- /* We want to send two extra-datasets
- * (the ResID of the Drawable and some text)
- * to our ImageDisplayer */
- // A Bundle is just like a pimped HashMap
- Bundle myExtras = new Bundle(2);
- // Add those to extra datasets
- myExtras.putString(CAPTION_TO_SHOW_MARKER, "Behind door " + buttonCaption + " is...");
- myExtras.putInteger(DRAWABLE_RESID_MARKER, drawableResID);
- /* Assign the Bundle to the Intent.
- * The Intent will 'carry' it to the
- * SubActivity, where we will read the values back */
- i.putExtras(myExtras);
- // We use SUB_ACTIVITY_REQUEST_CODE as an 'identifier'
- startSubActivity(i, IMAGESUBACTIVITY_ID);
- }
- };
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- setContentView(R.layout.calendar_layout);
- // Apply the Button-Listener to all Buttons from the xml-file
- applyListenerToButtons(myOcl);
- // Retrieve a dateString using the DateUtils
- String dateString = DateUtils.dateString(
- System.currentTimeMillis()).toString();
- // Get the notification manager serivce.
- NotificationManager nm = (NotificationManager)
- getSystemService(NOTIFICATION_SERVICE);
- /* Show a message showing the current date */
- nm.notifyWithText(NOTIFICATION_ID,"Today is: " + dateString + "\n\t\tdon't cheat <img src="http://www.anddev.org/images/smilies/wink.png" alt=";)" title="Wink" />",
- NotificationManager.LENGTH_LONG, null);
- }
- private void applyListenerToButtons(OnClickListener aOcl){
- // 1 to 10
- findViewById(R.id.cmd_door_1).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_2).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_3).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_4).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_5).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_6).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_7).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_8).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_9).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_10).setOnClickListener(aOcl);
- // 11 to 20
- findViewById(R.id.cmd_door_11).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_12).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_13).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_14).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_15).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_16).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_17).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_18).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_19).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_20).setOnClickListener(aOcl);
- // 21 to 24
- findViewById(R.id.cmd_door_21).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_22).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_23).setOnClickListener(aOcl);
- findViewById(R.id.cmd_door_24).setOnClickListener(aOcl);
- }
- }
Parsed in 0.058 seconds, using GeSHi 1.0.8.4
'src/your_package_structure/ImageDisplayer.java'
Using java Syntax Highlighting
- package org.anddev.android.christmascalendar;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.ImageView;
- public class ImageDisplayer extends Activity{
- /** Called when the activity is first created. */
- @Override
- public void onCreate(Bundle icicle) {
- super.onCreate(icicle);
- // Apply our subactivity.xml-Layout
- setContentView(R.layout.imagedisplayer_layout);
- // Read out the passed title and apply it
- String captionToShow = getIntent().getExtras()
- .getString(ChristmasCalendar.CAPTION_TO_SHOW_MARKER);
- this.setTitle(captionToShow);
- // Find the ImageView from our xml-layout
- ImageView iv = (ImageView)findViewById(R.id.image);
- // Read out the drawableResID
- int drawableResID = getIntent().getExtras()
- .getInteger(ChristmasCalendar.DRAWABLE_RESID_MARKER);
- iv.setImageResource(drawableResID); // apply it
- iv.invalidate(); // ensures at least one redraw
- // Find the button defined in the subactivity.xml
- Button cmd_return = (Button)findViewById(R.id.subactivity_cmd_return);
- /* Add an OnClickListener to it, that close this activity */
- cmd_return.setOnClickListener(new OnClickListener(){
- // @Override
- public void onClick(View arg0) {
- // Close this Activity
- ImageDisplayer.this.finish();
- }
- });
- }
- }
Parsed in 0.041 seconds, using GeSHi 1.0.8.4
Regards,
plusminus




300.. in just 3 weeks is really much 

