Defining the Puzzle View Class

Next we need to define the PuzzleView class. Instead of using an XML layout, this time let's do it entirely in Java.

Download from Library of Wow! eBook <www.wowebook.com>

What Size Is It Anyway?

A common mistake made by new Android developers is to use the width and height of a view inside its constructor. When a view's constructor is called, Android doesn't know yet how big the view will be, so the sizes are set to zero. The real sizes are calculated during the layout stage, which occurs after construction but before anything is drawn. You can use the onSizeChanged() method to be notified of the values when they are known, or you can use the getWidth() and getHeight() methods later, such as in the onDraw() method.

Here's the outline:

Download Sudokuv2/src/org/example/sudoku/PuzzleView.java

package org.example.sudoku;

import 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.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 static final String TAG = "'Sudoku"; private final Game game; public PuzzleView(Context context) { super(context); this.game = (Game) context; setFocusable(true); setFocusableInTouchMode(true);

In the constructor we keep a reference to the Game class and set the option to allow user input in the view. Inside PuzzleView, we need to implement the onSizeChanged() method. This is called after the view is created and Android knows how big everything is.

Other Ways to Do It

When I was writing this example, I tried several different approaches such as using a button for each tile or declaring a grid of imageView classes in XML. After many false starts, I found that the approach of having one view for the entire puzzle and drawing lines and numbers inside that proved to be the fastest and easiest way for this application.

It does have its drawbacks, though, such as the need to draw the selection and explicitly handle keyboard and touch events. When designing your own program, I recommend trying standard widgets and views first and then falling back to custom drawing only if that doesn't work for you.

Download Sudokuv2/src/org/example/sudoku/PuzzleView.java

private float width; private float height; private int selX; private int selY;

// width of one tile // height of one tile // X index of selection // Y index of selection private final Rect selRect = new Rect();

@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { width = w / 9f; height = h / 9f; getRect(selX, selY, selRect);

Log.d(TAG, "onSizeChanged: width " + width + ", height "

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));

We use onSizeChanged() to calculate the size of each tile on the screen (1/9th of the total view width and height). Note this is a floating-point number, so it's possible that we could end up with a fractional number of pixels. selRect is a rectangle we'll use later to keep track of the selection cursor.

At this point we've created a view for the puzzle, and we know how big it is. The next step is to draw the grid lines that separate the tiles on the board.

0 0

Post a comment