PuzzleView.java
上传用户:xmjingguan
上传日期:2009-07-06
资源大小:2054k
文件大小:9k
源码类别:

android开发

开发平台:

Java

  1. /***  * Excerpted from "Hello, Android!",  * published by The Pragmatic Bookshelf.  * Copyrights apply to this code. It may not be used to create training material,   * courses, books, articles, and the like. Contact us if you are in doubt.  * We make no guarantees that this code is fit for any purpose.   * Visit http://www.pragmaticprogrammer.com/titles/eband for more book information. ***/
  2. package org.example.sudoku;
  3. import android.content.Context;
  4. import android.graphics.Canvas;
  5. import android.graphics.Paint;
  6. import android.graphics.Rect;
  7. import android.graphics.Paint.FontMetrics;
  8. import android.graphics.Paint.Style;
  9. import android.os.Bundle;
  10. import android.os.Parcelable;
  11. import android.util.Log;
  12. import android.view.KeyEvent;
  13. import android.view.MotionEvent;
  14. import android.view.View;
  15. import android.view.animation.AnimationUtils;
  16. public class PuzzleView extends View {
  17.    
  18.    private static final String TAG = "Sudoku";
  19.    
  20.    private static final String SELX = "selX";     private static final String SELY = "selY";
  21.    private static final String VIEW_STATE = "viewState";
  22.    private static final int ID = 42; 
  23.    
  24.    private float width;    // width of one tile
  25.    private float height;   // height of one tile
  26.    private int selX;       // X index of selection
  27.    private int selY;       // Y index of selection
  28.    private final Rect selRect = new Rect();
  29.    private final Game game;
  30.    
  31.    public PuzzleView(Context context) {
  32.       
  33.       super(context);
  34.       this.game = (Game) context;
  35.       setFocusable(true);
  36.       setFocusableInTouchMode(true);
  37.       
  38.       // ...
  39.       setId(ID);     }
  40.    @Override
  41.    protected Parcelable onSaveInstanceState() {        Parcelable p = super.onSaveInstanceState();
  42.       Log.d(TAG, "onSaveInstanceState");
  43.       Bundle bundle = new Bundle();
  44.       bundle.putInt(SELX, selX);
  45.       bundle.putInt(SELY, selY);
  46.       bundle.putParcelable(VIEW_STATE, p);
  47.       return bundle;
  48.    }
  49.    @Override
  50.    protected void onRestoreInstanceState(Parcelable state) {        Log.d(TAG, "onRestoreInstanceState");
  51.       Bundle bundle = (Bundle) state;
  52.       select(bundle.getInt(SELX), bundle.getInt(SELY));
  53.       super.onRestoreInstanceState(bundle.getParcelable(VIEW_STATE));
  54.       return;
  55.    }
  56.    
  57.    @Override
  58.    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  59.       width = w / 9f;
  60.       height = h / 9f;
  61.       getRect(selX, selY, selRect);
  62.       Log.d(TAG, "onSizeChanged: width " + width + ", height "
  63.             + height);
  64.       super.onSizeChanged(w, h, oldw, oldh);
  65.    }
  66.    @Override
  67.    protected void onDraw(Canvas canvas) {
  68.       // Draw the background...
  69.       Paint background = new Paint();
  70.       background.setColor(getResources().getColor(
  71.             R.color.puzzle_background));
  72.       canvas.drawRect(0, 0, getWidth(), getHeight(), background);
  73.       
  74.       // Draw the board...
  75.       
  76.       // Define colors for the grid lines
  77.       Paint dark = new Paint();
  78.       dark.setColor(getResources().getColor(R.color.puzzle_dark));
  79.       Paint hilite = new Paint();
  80.       hilite.setColor(getResources().getColor(R.color.puzzle_hilite));
  81.       Paint light = new Paint();
  82.       light.setColor(getResources().getColor(R.color.puzzle_light));
  83.       // Draw the minor grid lines
  84.       for (int i = 0; i < 9; i++) {
  85.          canvas.drawLine(0, i * height, getWidth(), i * height,
  86.                light);
  87.          canvas.drawLine(0, i * height + 1, getWidth(), i * height
  88.                + 1, hilite);
  89.          canvas.drawLine(i * width, 0, i * width, getHeight(),
  90.                light);
  91.          canvas.drawLine(i * width + 1, 0, i * width + 1,
  92.                getHeight(), hilite);
  93.       }
  94.       // Draw the major grid lines
  95.       for (int i = 0; i < 9; i++) {
  96.          if (i % 3 != 0)
  97.             continue;
  98.          canvas.drawLine(0, i * height, getWidth(), i * height,
  99.                dark);
  100.          canvas.drawLine(0, i * height + 1, getWidth(), i * height
  101.                + 1, hilite);
  102.          canvas.drawLine(i * width, 0, i * width, getHeight(), dark);
  103.          canvas.drawLine(i * width + 1, 0, i * width + 1,
  104.                getHeight(), hilite);
  105.       }
  106.       // Draw the numbers...
  107.       // Define color and style for numbers
  108.       Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
  109.       foreground.setColor(getResources().getColor(
  110.             R.color.puzzle_foreground));
  111.       foreground.setStyle(Style.FILL);
  112.       foreground.setTextSize(height * 0.75f);
  113.       foreground.setTextScaleX(width / height);
  114.       foreground.setTextAlign(Paint.Align.CENTER);
  115.       // Draw the number in the center of the tile
  116.       FontMetrics fm = foreground.getFontMetrics();
  117.       // Centering in X: use alignment (and X at midpoint)
  118.       float x = width / 2;
  119.       // Centering in Y: measure ascent/descent first
  120.       float y = height / 2 - (fm.ascent + fm.descent) / 2;
  121.       for (int i = 0; i < 9; i++) {
  122.          for (int j = 0; j < 9; j++) {
  123.             canvas.drawText(this.game.getTileString(i, j), i
  124.                   * width + x, j * height + y, foreground);
  125.          }
  126.       }
  127.       
  128.       if (Prefs.getHints(getContext())) {
  129.          // Draw the hints...
  130.          
  131.          // Pick a hint color based on #moves left
  132.          Paint hint = new Paint();
  133.          int c[] = { getResources().getColor(R.color.puzzle_hint_0),
  134.                getResources().getColor(R.color.puzzle_hint_1),
  135.                getResources().getColor(R.color.puzzle_hint_2), };
  136.          Rect r = new Rect();
  137.          for (int i = 0; i < 9; i++) {
  138.             for (int j = 0; j < 9; j++) {
  139.                int movesleft = 9 - game.getUsedTiles(i, j).length;
  140.                if (movesleft < c.length) {
  141.                   getRect(i, j, r);
  142.                   hint.setColor(c[movesleft]);
  143.                   canvas.drawRect(r, hint);
  144.                }
  145.             }
  146.          }
  147.          
  148.       }
  149.       
  150.       // Draw the selection...
  151.       Log.d(TAG, "selRect=" + selRect);
  152.       Paint selected = new Paint();
  153.       selected.setColor(getResources().getColor(
  154.             R.color.puzzle_selected));
  155.       canvas.drawRect(selRect, selected);
  156.    }
  157.    @Override
  158.    public boolean onTouchEvent(MotionEvent event) {
  159.       if (event.getAction() != MotionEvent.ACTION_DOWN)
  160.          return super.onTouchEvent(event);
  161.       select((int) (event.getX() / width),
  162.             (int) (event.getY() / height));
  163.       game.showKeypadOrError(selX, selY);
  164.       Log.d(TAG, "onTouchEvent: x " + selX + ", y " + selY);
  165.       return true;
  166.    }
  167.    @Override
  168.    public boolean onKeyDown(int keyCode, KeyEvent event) {
  169.       Log.d(TAG, "onKeyDown: keycode=" + keyCode + ", event="
  170.             + event);
  171.       switch (keyCode) {
  172.       case KeyEvent.KEYCODE_DPAD_UP:
  173.          select(selX, selY - 1);
  174.          break;
  175.       case KeyEvent.KEYCODE_DPAD_DOWN:
  176.          select(selX, selY + 1);
  177.          break;
  178.       case KeyEvent.KEYCODE_DPAD_LEFT:
  179.          select(selX - 1, selY);
  180.          break;
  181.       case KeyEvent.KEYCODE_DPAD_RIGHT:
  182.          select(selX + 1, selY);
  183.          break;
  184.       case KeyEvent.KEYCODE_0:
  185.       case KeyEvent.KEYCODE_SPACE: setSelectedTile(0); break;
  186.       case KeyEvent.KEYCODE_1:     setSelectedTile(1); break;
  187.       case KeyEvent.KEYCODE_2:     setSelectedTile(2); break;
  188.       case KeyEvent.KEYCODE_3:     setSelectedTile(3); break;
  189.       case KeyEvent.KEYCODE_4:     setSelectedTile(4); break;
  190.       case KeyEvent.KEYCODE_5:     setSelectedTile(5); break;
  191.       case KeyEvent.KEYCODE_6:     setSelectedTile(6); break;
  192.       case KeyEvent.KEYCODE_7:     setSelectedTile(7); break;
  193.       case KeyEvent.KEYCODE_8:     setSelectedTile(8); break;
  194.       case KeyEvent.KEYCODE_9:     setSelectedTile(9); break;
  195.       case KeyEvent.KEYCODE_ENTER:
  196.       case KeyEvent.KEYCODE_DPAD_CENTER:
  197.          game.showKeypadOrError(selX, selY);
  198.          break;
  199.       default:
  200.          return super.onKeyDown(keyCode, event);
  201.       }
  202.       return true;
  203.    }
  204.    public void setSelectedTile(int tile) {
  205.       if (game.setTileIfValid(selX, selY, tile)) {
  206.          invalidate();// may change hints
  207.       } else {
  208.          // Number is not valid for this tile
  209.          Log.d(TAG, "setSelectedTile: invalid: " + tile);
  210.          startAnimation(AnimationUtils.loadAnimation(game,
  211.                R.anim.shake));
  212.       }
  213.    }
  214.    private void select(int x, int y) {
  215.       invalidate(selRect);
  216.       selX = Math.min(Math.max(x, 0), 8);
  217.       selY = Math.min(Math.max(y, 0), 8);
  218.       getRect(selX, selY, selRect);
  219.       invalidate(selRect);
  220.    }
  221.    private void getRect(int x, int y, Rect rect) {
  222.       rect.set((int) (x * width), (int) (y * height), (int) (x
  223.             * width + width), (int) (y * height + height));
  224.    }
  225.    
  226.    // ...
  227. }