Understanding Android UI and Intents by Implementing Sudoku Uichin Lee KAIST KSE March 14, 2013...
-
Upload
victor-little -
Category
Documents
-
view
224 -
download
0
Transcript of Understanding Android UI and Intents by Implementing Sudoku Uichin Lee KAIST KSE March 14, 2013...
Understanding Android UI and Intents by Implementing Sudoku
Uichin LeeKAIST KSE
March 14, 2013
Hello, Android Chapter 3
Objective:
• Review Android Sudoku Example to understand Android User Interfaces and Intents
Filling a 9×9 grid with digits so that each column, each row, and each of the nine 3×3 sub-grids that compose the grid contains all of the digits from 1 to 9
Getting Started
• UI Design methods:– Procedural design: written in Java code (like Swing, e.g.,
JButton, JFrame)– Declarative design: XML description of UI objects
• Preferred method
• Creating the Opening ScreenProject name: SudokuBuild target: Android 2.2Application name: SudokuPackage name: org.example.sudokuCreate Activity: SudokuMin SDK Version: 8
Android – User InterfacesUsing XML Layouts
Victor MatosCleveland State University
Notes are based on: The Busy Coder's Guide to Android Developmentby Mark L. MurphyCopyright © 2008-2009 CommonsWare, LLC.ISBN: 978-0-9816780-0-9&Android Developers http://developer.android.com/index.html
Part 4
5
4. Android – UI - User Interfaces
The View Class
5
• The View class represents the basic building block for user interface components.
• A View occupies a rectangular area on the screen and is responsible for drawing and event-handling.
• View is the base class for widgets that are used to create interactive UI components (buttons, text fields, etc.).
• The ViewGroup subclass (of View) is the base class for layouts, which are invisible containers that can hold other Views (or other ViewGroups) and define their layout properties.
6
4. Android – UI - User Interfaces
Using Views
6
All of the views in a window are arranged in a single tree. You can add views either from code or by specifying a tree of views in one or more XML layout files.
Once you have created a tree of views, there are typically a few types of common operations you may wish to perform:
1. Set properties: for example setting the text of a TextView. Properties that are known at build time can be set in the XML layout files.
2. Set focus: The framework will handled moving focus in response to user input. To force focus to a specific view, call requestFocus().
3. Set up listeners: Views allow clients to set listeners that will be notified when something interesting happens to the view. For example, a Button exposes a listener to notify clients when the button is clicked.
4. Set visibility: You can hide or show views using setVisibility(int).
7
4. Android – UI - User Interfaces
A brief sample of UI components
7
Linear LayoutA LinearLayout is a GroupView that will lay child View elements vertically or horizontally.
Relative LayoutA RelativeLayout is a ViewGroup that allows you to layout child elements in positions relative to the parent or siblings elements.
Table Layout A TableLayout is a ViewGroup that will lay child View elements into rows and columns.
Layouts
8
4. Android – UI - User Interfaces
A brief sample of UI components
8
DatePickerA DatePicker is a widget that allows the user to select a month, day and year.
Form ControlsIncludes a variety of typical form widgets, like: image buttons, text fields, checkboxes and radio buttons.
GalleryView
TabWidget
Spinner
Widgets
9
4. Android – UI - User Interfaces
A brief sample of UI components
9
AutoCompleteTextViewIt is a version of the EditText widget that will provide auto-complete suggestions as the user types. The suggestions are extracted from a collection of strings.
ListViewA ListView is a View that shows items in a vertically scrolling list. The items are acquired from a ListAdapter.
WebView
MapView
10
4. Android – UI - User Interfaces
What is an XML Layout?
An XML-based layout is a specification of the various UI components and the relationships to each other – and to their containers – all written in XML format.
10
Android considers XML-based layouts to be resources, and as such layout files are stored in the res/layout directory inside your Android project.
11
4. Android – UI - User Interfaces
What is an XML Layout?
Each XML file contains a tree of elements specifying a layout of widgets and containers that make up one View (shown later).
The attributes of the XML elements are properties, describing how a widget should look or how a container should behave.
Example: If a Button element has an attribute value of
android:textStyle = "bold" that means that the text appearing on the face of the button should be rendered in a boldface font style.
11
12
4. Android – UI - User Interfaces
An example
12
The application places a button to occupy the screen. When clicked the button’s text shows current time.import java.util.Date;import android.app.Activity;import android.os.Bundle;import android.view.View;import android.view.View.OnClickListener;import android.widget.Button;
public class AndDemo extends Activity {Button btn;
@Overridepublic void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); btn = (Button) findViewById(R.id.myButton); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { updateTime(); } }); }// onCreate//private void updateTime() { btn.setText(new Date().toString());}
}
13
4. Android – UI - User Interfaces
An example
13
This is the XML-Layout definition
<?xml version="1.0" encoding="utf-8"?><Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/myButton" android:text="" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
The root element needs to declare the Android XML namespace:xmlns:android="http://schemas.android.com/apk/res/android"
All other elements will be children of the root and will inherit that namespace declaration.
Because we want to reference this button from our Java code, we need to giveit an identifier via the android:id attribute.
14
4. Android – UI - User Interfaces
An example cont.
14
<?xml version="1.0" encoding="utf-8"?><Button xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/myButton" android:text="" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
The remaining attributes are properties of this Button instance:
• android:text indicates the initial text to be displayed on the button face (in this case, an empty string)
• android:layout_width and android:layout_height tell Android to have the button's width and height fill the "parent“ container, in this case the entire screen.
15
4. Android – UI - User Interfaces
UI Hierarchy
15
The utility HierarchyViewer displays the UI structure of the current screen shown on the emulator or device (eclipse: Windows > Open Perspectives)
(Execute app on emulator, execute HierarchyViewer, click on Emulator > Refresh Screenshot )
UI Tree
4. Android – UI - User Interfaces
UI HierarchyExample: Display UI Hierarchy
UI Tree
<?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" ><TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /></LinearLayout>
17
4. Android – UI - User Interfaces
Attaching Layouts to Java Code
17
PLUMBING. You must ‘connect’ the XML elements with equivalent objects in your Java activity. This allows you to manipulate the UI with code.
XLM Layout<xml….. . . . . .</xml>
JAVA codepublic class ….{. . . . . .}
18
4. Android – UI - User Interfaces
Attaching Layouts to Java Code
18
Assume the UI in res/layout/main.xml has been created. This layout could be called by an application using the statement
setContentView(R.layout.main);
Individual widgets, such as myButton could be accessed by the application using the statement findViewByID(...) as in
Button btn = (Button) findViewById(R.id.myButton);
Where R is a class automatically generated to keep track of resources available to the application. In particular R.id... is the collection of widgets defined in the XML layout.
19
4. Android – UI - User Interfaces
Attaching Layouts to Java Code
19
Where R is a class automatically generated to keep track of resources available to the application. In particular R.id... is the collection of widgets defined in the XML layout.
/* AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated by the * aapt tool from the resource data it found. It * should not be modified by hand. */
package uichin.kaist;
public final class R { public static final class attr { } public static final class drawable { public static final int icon=0x7f020000; } public static final class layout { public static final int main=0x7f030000; } public static final class string { public static final int app_name=0x7f040001; public static final int hello=0x7f040000; }}
20
4. Android – UI - User Interfaces
Attaching Layouts to Java Code
20
Attaching Listeners to the Widgets
The button of our example could now be used, for instance a listener for the click event could be written as:
btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { updateTime(); }});
private void updateTime() { btn.setText(new Date().toString());}
Sudoku Overview
(1) Main Layout XML
Sudoku.java(2) About
About.java(5) Draw Game
Game.javaPuzzleView.java
(3) Menu KeySudoku.java
(6) Key Pad
Keypad.java
Touch
Preference: Menu
Pref.java
(4) New Game
Step 1: Main Layout<?xml version="1.0" encoding="utf-8"?><LinearLayout
xmlns:android="http://schemas.../android"android:background="@color/background"android:layout_height="fill_parent"android:layout_width="fill_parent"android:padding="30dip"android:orientation="horizontal" ><LinearLayoutandroid:orientation="vertical"android:layout_height="wrap_content"android:layout_width="fill_parent"android:layout_gravity="center" ><TextView
android:text="@string/main_title"android:layout_height="wrap_content"android:layout_width="wrap_content"android:layout_gravity="center"android:layout_marginBottom="25dip"android:textSize="24.5sp" />
<Buttonandroid:id="@+id/continue_button"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/continue_label" />
<Buttonandroid:id="@+id/exit_button"android:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/exit_label" />
...more buttons..’</LinearLayout>
</LinearLayout>
<resources> <string name="app_name">Sudoku</string> <string name="main_title">Android Sudoku</string> <string name="continue_label">Continue</string> <string name="new_game_label">New Game</string> <string name="about_label">About</string> <string name="exit_label">Exit</string>
Step 1: Main Layout
Use “GraphicalLayout”
Step 1: Main Layout
• Emulator: Ctrl + F11 (rotate screen)• Add a new layout for the landscape mode (use “-land” suffix)
– Select res, Ctrl+N, select Android/Android XML Layout File/
Step 1: Main Layout• Set up click listeners for all the buttons
import android.app.Activity;import android.os.Bundle;import android.content.Intent;import android.view.View;import android.view.View.OnClickListener;
public class Soduku extends Activity implements OnClickListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.about);
// Set up click listeners for all the buttonsView continueButton = findViewById(R.id.continue_button);continueButton.setOnClickListener(this);View newButton = findViewById(R.id.new_button);newButton.setOnClickListener(this);View aboutButton = findViewById(R.id.about_button);aboutButton.setOnClickListener(this);View exitButton = findViewById(R.id.exit_button);exitButton.setOnClickListener(this);
}}
Step 1: Main Layout• onClick handler
public void onClick(View v) { switch (v.getId()) { case R.id.continue_button:
Intent intent = new Intent(Sudoku.this, Game.class); intent.putExtra(Game.KEY_DIFFICULTY, Game.DIFFICULTY_CONTINUE); startActivity(intent);
break;
case R.id.about_button: Intent i = new Intent(this, About.class); startActivity(i); break;
// More buttons go here (if any) ... case R.id.new_button: openNewGameDialog(); break;
case R.id.exit_button: finish(); break; } }
(4) New Game(2) About
Continue
Shut down activity and return control
Android Intents
Part 2Inter-Process Communication Using Bundles
Victor MatosCleveland State University
Notes are based on: Android Developers http://developer.android.com/index.html
12-2
28
12. Android – Intents – Part 2
Intents
28
Android IntentsAn activity usually presents a single visual user interface from which a number of actions could be performed.
Moving from one activity to another is accomplished by having the current activity start the next one through so called intents.
Intent {action + data}
requestCoderequestResult[ optional data ]
Activity-1
startActivityForResult…
onActivityResult()…
Activity-2
onResult()……
29
12. Android – Intents – Part 2
Intents
29
Android Bundles
Most programming languages support the notion of IPC (Inter-Process Communication) method-calling with arguments flowing birectionally from the caller to the invoked method.
In android the calling activity issues an invocation to another activity using an Intent object.
Notably in Android, the caller does not wait for the called activity to return results. Instead a listening-method [onActivityResult(...) ] should be used.
IPC Inter-Process Communication
30
12. Android – Intents – Part 2
Intents
30
Android Bundles
Normally the IPC expressions actual parameter list, and formal parameter list are used to designate the signature of particpating arguments, and the currently supplied data.
Instead of using the traditional formal/actual parameter lists, Android relies on the concept of Intents to establish Inter-process-communication.
Intents optionally carry a named actual list or bundle for data exchange.
31
12. Android – Intents – Part 2
Intents
31
Android Bundles
The Android Bundle container is a simple mechanism used to pass data between activities.
A Bundle is a type-safe collection of <name, value> pairs.
There is a set of putXXX and getXXX methods to store and retrieve (single and array) values of primitive data types from/to the bundles. For example
Bundle myBundle = new Bundle();myBundle.putDouble (“var1”, 3.1415);
...Double v1 = myBundle.getDouble(“var1”);
32
Intent myIntentA1A2 = new Intent (Activity1.this, Activity2.class);
Bundle myBundle1 = new Bundle();myBundle1.putInt (“val1”, 123);
myIntentA1A2.putExtras(myBundle1);
startActivityForResult(myIntentA1A2, 1122);
12. Android – Intents – Part 2
Intents
32
Android Intents & Bundles
Activity1: Sender Activity2: Receiver
INTENT
requestCode (1122)
resultCode
Extras: { val1 = 123 }
Sender class / Receiver class
Bundles
33
12. Android – Intents – Part 2
Intents
33
Android Intents & Bundles
Activity1: Sender Activity2: Receiver
INTENT
requestCode (1122)
resultCode
Extras: { val1 = 123 }
Sender class / Receiver class
Intent myLocalIntent2 = getIntent();
Bundle myBundle = myLocalIntent.getExtras();
int val1 = myBundle.getInt(“val1");
34
12. Android – Intents – Part 2
Intents
34
Android Intents & Bundles
Activity1: Sender Activity2: Receiver
INTENT
requestCode (1122)
resultCode (OK)
Extras: { val1 = 456 }
Sender class / Receiver class
myBundle.putString("val1", 456 );
myLocalIntent.putExtras(myBundle);
setResult(Activity.RESULT_OK, myLocalIntent);
Sudoku
Touch(1) Main Layout XML
(2) About
Preference: Menu
(3) Menu Key
(4) New Game
(5) Draw Game
(6) Key Pad
Sudoku.java
About.javaGame.java
PuzzleView.java
Keypad.java
Sudoku.java
Pref.java
Step 2: About Window• Draw a window with some info about Sudoku
– Define a new Activity, and start it– Use the AlertDialog class, and show it– Subclass Android’s Dialog class, and show that
• How to add a new Activity class in Eclipse?1. (create a new class) File > New > Class:
• Superclass: android.app.Activity
2. (activity registration) AndroidManitest.xml > Application > Application Nodes• Or manually type in <activity…> </activity> in the XML file
3. Auto-filling Override functions: Right click “About.java” > Source > Override/Implement methods > Select “onCreate”
Register a new activity here
<activity android:name=".About“></activity>
Step 2: About Window
• Adding a new layout? (about.xml)– New > Other > Android > Android XML Layout File
• This will automatically add R.layout.about (in R.java)
ScrollView
about.xml
“Layout”
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:padding="10dip"> <TextView android:id="@+id/about_content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/about_text" /></ScrollView>
Step 2: About Window
package org.example.sudoku;
import android.app.Activity;import android.os.Bundle;
public class About extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Set “about.xml” layout as a default view setContentView(R.layout.about); }}
Step 2: About Window
• Applying a theme– Very similar to Cascading Style Sheets (CSS) used for
web pages– Default styles, and user-defined styles
• Using a default theme: AndroidMenifest.xml
– “@android:” prefix means that it’s a reference to a resource defined by Android
<activity android:name=".About“android:label="@string/about_title“android:theme="@android:style/Theme.Dialog">
</activity>
Sudoku
Touch(1) Main Layout XML
(2) About
Preference: Menu
(3) Menu Key
(4) New Game
(5) Draw Game
(6) Key Pad
Sudoku.java
About.javaGame.java
PuzzleView.java
Keypad.java
Sudoku.java
Pref.java
Step 3: Adding a Menu/Setting
• Menus in Android:– When you press the physical Menu button
• Recent Androids (API 11 and higher) has a soft menu button instead (called an overflow menu button)
– Context menu popping up when you press and hold your finger on the screen
• Implementing “physical (or soft) menu”1. Define string labels that will be used in menu
(res/values/strings.xml)2. Define a menu using XML (res/menu/menu.xml) • New > Other > Android > Android XML File (select “menu”)
Step 3: Adding a Menu/Setting
• Bring up a menu: Sudoku.javaimport android.view.Menu;import android.view.MenuInflater;import android.view.MenuItem;
@Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.menu, menu); return true; }
@Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.settings: startActivity(new Intent(this, Prefs.class)); return true; // More items go here (if any) ... } return false; }
Read menu definition from
xml file
Called when a user selects any
menu item
Step 3: Adding a Menu/Setting
• Bring up a setting: Pref.java1. Create a new layout (choose “Preference”): stored in
“res/xml” by default2. Create a class “Pref.java” (extends “PreferenceActivity”)• Register Activity in the AndroidMenifest.xml
<PreferenceScreenxmlns:android="http://schemas.android.com/apk/res/android"> <CheckBoxPreference android:key="music" android:title="@string/music_title" android:summary="@string/music_summary" android:defaultValue="true" /> <CheckBoxPreference android:key="hints" android:title="@string/hints_title" android:summary="@string/hints_summary" android:defaultValue="true" /></PreferenceScreen>
import android.content.Context;import android.os.Bundle;import android.preference.PreferenceActivity;import android.preference.PreferenceManager;
public class Prefs extends PreferenceActivity {@Overrideprotected void onCreate(Bundle savedInstanceState){ super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings);}}
setting.xml (layout)Pref.java
Sudoku
Touch(1) Main Layout XML
(2) About
Preference: Menu
(3) Menu Key
(4) New Game
(5) Draw Game
(6) Key Pad
Sudoku.java
About.javaGame.java
PuzzleView.java
Keypad.java
Sudoku.java
Pref.java
Step 4: New Game Menu• Pop up a dialog box, asking users to select among three difficulty
levels (AlertDialog)import android.app.AlertDialog;import android.content.DialogInterface;import android.util.Log;
public class Sudoku extends Activity implements OnClickListener { private void openNewGameDialog() { new AlertDialog.Builder(this) .setTitle(R.string.new_game_title) .setItems(R.array.difficulty, new DialogInterface.OnClickListener() { public void onClick(DialogInterface dialoginterface, int i) { startGame(i); } }) .show(); }private void startGame(int i) { Log.d(TAG, "clicked on " + i); Intent intent = new Intent(Sudoku.this, Game.class); intent.putExtra(Game.KEY_DIFFICULTY, i); startActivity(intent); }}
<resources> <array name="difficulty"> <item>@string/easy_label</item> <item>@string/medium_label</item> <item>@string/hard_label</item> </array></resources>
Sudoku.java
Debugging• Debugging with Log Messages
– Log class provides several static methods to print messages of various levels• Log.e(): errors• Log.w(): warnings• Log.i(): information• Log.d(): debugging• Log.v(): verbose• Log.wtf(): what a terrible failure
– Eclipse: Window > Show View > Other > Android > LogCat • Debugging with Eclipse debugger
– Must enable debugging: AndroidManifest.xml<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.example.sudoku" android:versionCode="1" android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name“
android:debuggable=“true”>
Sudoku
Touch(1) Main Layout XML
(2) About
Preference: Menu
(3) Menu Key
(4) New Game
(5) Draw Game
(6) Key Pad
Sudoku.java
About.javaGame.java
PuzzleView.java
Keypad.java
Sudoku.java
Pref.java
Activity-2 (Game)
Step 5: Starting a Game
• Procedure:1. Start a new activity (Game)
• Game.java
2. Game initializes its view using PuzzleView• PuzzleView.java
Intent {action + data}
Activity-1(Sudoku)
startActivity()
Intent intent = new Intent(Sudoku.this, Game.class);intent.putExtra(Game.KEY_DIFFICULTY, i);startActivity(intent);
protected void onCreate(savedInstanceState) {int diff = getIntent().getIntExtra(KEY_DIFFICULTY, DIFFICULTY_EASY);puzzleView = new PuzzleView(this);setContentView(puzzleView);
PuzzleView
Step 5: Starting a Game – PuzzleView
• Android 2D graphic package:– Color
• E.g., color = Color.argb(127, 255, 0, 255) or color = getResources().getColor(R.color.mycolor)
– Paint• Style, color, and other info needed to draw any graphics such as
bitmaps, text, and geometric shapes
– Canvas: a surface on which you draw! • Display is taken up by an Activity, which hosts a View, which in turn
hosts Canvas• Drawing on the canvas by overriding the View.onDraw() method
– Path– Drawable: bitmap, Shape, etc.
Step 5: Starting a Game – PuzzleViewimport android.content.Context;import android.graphics.Canvas;import android.graphics.Paint;import android.graphics.Rect;import android.graphics.Paint.FontMetrics;import android.graphics.Paint.Style;
import android.os.Bundle;import android.os.Parcelable;
import android.util.Log;import android.view.KeyEvent;import android.view.MotionEvent;import android.view.View;import android.view.animation.AnimationUtils;
public class PuzzleView extends View { private final Game game; public PuzzleView(Context context) {
super(context); this.game = (Game) context;
setFocusable(true); setFocusableInTouchMode(true);
}
private float width; // width of one tileprivate float height; // height of one tileprivate static final String SELX = "selX"; private static final String SELY = "selY";private final Rect selRect = new Rect();
@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) { width = w / 9f; height = h / 9f; getRect(selX, selY, selRect); super.onSizeChanged(w, h, oldw, oldh); }
private void getRect(int x, int y, Rect rect) { rect.set((int) (x * width), (int) (y * height), (int) (x * width + width), (int) (y * height + height));}
onSizeChanged() is called after the view is created
Step 5: Starting a Game - PuzzleView
• Drawing the board– onDraw() method is called anytime the view needs to be
updated
@Override protected void onDraw(Canvas canvas) {
// Draw the background... Paint background = new Paint();
background.setColor(getResources().getColor( R.color.puzzle_background));
canvas.drawRect(0, 0, getWidth(), getHeight(), background);
Step 5: Starting a Game - PuzzleView• Drawing the grid lines for the board // Define colors for the grid lines Paint dark = new Paint(); dark.setColor(getResources().getColor(R.color.puzzle_dark)); Paint hilite = new Paint(); hilite.setColor(getResources().getColor(R.color.puzzle_hilite)); Paint light = new Paint(); light.setColor(getResources().getColor(R.color.puzzle_light));
// Draw the minor grid lines for (int i = 0; i < 9; i++) { canvas.drawLine(0, i * height, getWidth(), i * height, light); canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, hilite); canvas.drawLine(i * width, 0, i * width, getHeight(), light); canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilite); }
// Draw the major grid lines for (int i = 0; i < 9; i++) { if (i % 3 != 0) continue; canvas.drawLine(0, i * height, getWidth(), i * height, dark); canvas.drawLine(0, i * height + 1, getWidth(), i * height + 1, hilite); canvas.drawLine(i * width, 0, i * width, getHeight(), dark); canvas.drawLine(i * width + 1, 0, i * width + 1, getHeight(), hilite); }
Step 5: Starting a Game - PuzzleView• Drawing the numbers
// Define color and style for numbers Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG); foreground.setColor(getResources().getColor(R.color.puzzle_foreground)); foreground.setStyle(Style.FILL); foreground.setTextSize(height * 0.75f); foreground.setTextScaleX(width / height); foreground.setTextAlign(Paint.Align.CENTER);
// Draw the number in the center of the tile FontMetrics fm = foreground.getFontMetrics();
// Centering in X: use alignment (and X at midpoint) float x = width / 2;
// Centering in Y: measure ascent/descent first float y = height / 2 - (fm.ascent + fm.descent) / 2; for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { canvas.drawText(this.game.getTileString(i, j), i * width + x, j * height + y, foreground); } }
Sudoku
Touch(1) Main Layout XML
(2) About
Preference: Menu
(3) Menu Key
(4) New Game
(5) Draw Game
(6) Key Pad
Sudoku.java
About.javaGame.java
PuzzleView.java
Keypad.java
Sudoku.java
Pref.java
Step 6: Handling Input• Procedure
1. Create a new layout for keypad (buttons!)2. Create a new class, Keypad that extends Dialog
public class Keypad extends Dialog {
private final View keys[] = new View[9];private View keypad;
private final int useds[];private final PuzzleView puzzleView;
public Keypad(Context context, int useds[], PuzzleView puzzleView) { super(context); this.useds = useds; this.puzzleView = puzzleView; }
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setTitle(R.string.keypad_title); setContentView(R.layout.keypad);
findViews(); // keys, keypad Views
for (int element : useds) { if (element != 0) keys[element-1].setVisibility(View.INVISIBLE); }
// for each key, keypad view, // set up OnClickListener() setListeners(); }
Cf. As of J2SE 5.0, Java allows you to iterate through a collection (array): http://www.java-tips.org/java-se-tips/java.lang/the-enhanced-for-loop.html
Step 6: Handling Input• PuzzleView:
– Keyboard: if a key is down, onKeyDown()is invoked– Touch: if a user touches the screen, onTouchEvent()is invoked– Then, display keypad: game.showKeypadOrError(selX, selY)
@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: select(selX - 1, selY); break; case KeyEvent.KEYCODE_DPAD_RIGHT: select(selX + 1, selY); break; case KeyEvent.KEYCODE_0: case KeyEvent.KEYCODE_SPACE: setSelectedTile(0); break; case KeyEvent.KEYCODE_1: setSelectedTile(1); break; case KeyEvent.KEYCODE_ENTER: case KeyEvent.KEYCODE_DPAD_CENTER: game.showKeypadOrError(selX, selY); break; default: return super.onKeyDown(keyCode, event); } return true;}
@Overridepublic boolean onTouchEvent(MotionEvent event) { if (event.getAction() != MotionEvent.ACTION_DOWN) return super.onTouchEvent(event);
select((int) (event.getX() / width), (int) (event.getY() / height));
game.showKeypadOrError(selX, selY); return true; }
Step 6: Handling Input• Showing keypad and returning the result
/** Open the keypad if there are any valid moves */ protected void showKeypadOrError(int x, int y) { int tiles[] = getUsedTiles(x, y); if (tiles.length == 9) { Toast toast = Toast.makeText(this, R.string.no_moves_label, Toast.LENGTH_SHORT); toast.setGravity(Gravity.CENTER, 0, 0); toast.show(); } else { Log.d(TAG, "showKeypad: used=" + toPuzzleString(tiles)); Dialog v = new Keypad(this, tiles, puzzleView); v.show(); } }
Game.java
private void returnResult(int tile) { puzzleView.setSelectedTile(tile); dismiss(); // dismissing a dialog from screen } Keypad.java
<string name="no_moves_label">
No moves</string>
strings.xml