我正在Android上开发Sudoku应用程序,但不能阻止我的自定义视图(sudoku面板)覆盖自身。我对应用程序开发非常陌生,所以我无法理解正在发生的事情。基本上,当我将棋盘传递给GameActivity时,其中的自定义视图会在较旧的棋盘上绘制新棋盘。这不应该发生。任何帮助都会得到应用。
这是我的自定义视图。
public class SudokuBoardView extends View {
private static final String TAG = "SUDOKUVIEWGRID";
//Paints
private Paint thinPaint;
private Paint thickPaint;
private Paint selectedCellPaint;
private Paint textPaint;
//Values
private static int width;
private static int height;
private static final int padding = 64;
private static final int SIZE = 9;
private static final int SQRT_SIZE = 3;
private float cellSizePixels;
//Model
private SudokuModel sudokuModel = null;
public SudokuBoardView(Context context) {
super(context);
init(null);
}
public SudokuBoardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public SudokuBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
public SudokuBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init(attrs);
}
public void init(@Nullable AttributeSet attributeSet) {
//Paint più sottile per celle
thinPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thinPaint.setStrokeWidth(2);
thinPaint.setStyle(Paint.Style.STROKE);
thinPaint.setColor(Color.BLACK);
//Paint più spesso per contorni
thickPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
thickPaint.setStrokeWidth(10);
thickPaint.setStyle(Paint.Style.STROKE);
thickPaint.setColor(Color.BLACK);
//Paint per celle selezionate
selectedCellPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
selectedCellPaint.setColor(Color.BLUE);
selectedCellPaint.setStyle(Paint.Style.FILL_AND_STROKE);
//Paint per numeri
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setTextSize(32);
textPaint.setColor(Color.BLACK);
//Dimensioni della griglia e delle celle
width = getResources().getDisplayMetrics().widthPixels; //Dim. assoluta dello schermo
height = getResources().getDisplayMetrics().heightPixels;
cellSizePixels = (float) ((width - 2*padding)/ SIZE);
}
public void setSudokuModel(SudokuModel model) {
this.sudokuModel = model;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//Outside Border
canvas.drawRoundRect(padding,padding, width - padding, width - padding, 20, 20, thickPaint);
//Cells
drawLines(canvas);
if (sudokuModel.isNewGame()) {
drawInitialBoard(canvas, sudokuModel.getBoard());
}
}
public void cleanCells() {
invalidate();
}
protected void drawLines(Canvas canvas){
//Linee Verticali
for (int i = 0; i < SIZE; i++) {
//Linea più spessa ogni 3 linee (la prima viene saltata perché c'è già il bordo)
if (i == 0) continue;
if (i % SQRT_SIZE == 0) {
canvas.drawLine( i*cellSizePixels + padding, padding, i*cellSizePixels + padding, width - padding, thickPaint);
} else {
canvas.drawLine( i*cellSizePixels + padding, padding, i*cellSizePixels + padding, width - padding, thinPaint);
}
}
//Linee Orizzontali
for (int i = 0; i < SIZE; i++) {
//Linea più spessa ogni 3 linee (la prima viene saltata perché c'è già il bordo)
if (i == 0) continue;
if (i % SQRT_SIZE == 0) {
canvas.drawLine( padding, i*cellSizePixels + padding, width - padding, i*cellSizePixels + padding, thickPaint);
} else {
canvas.drawLine(padding, i * cellSizePixels + padding, width - padding, i * cellSizePixels + padding, thinPaint);
}
}
}
public void drawInitialBoard(Canvas canvas, Board board) {
for (Cell cell: board.getCellList()) {
int value = cell.getValue();
String valueText = Integer.toString(value);
int row = cell.getRow();
int col = cell.getCol();
Rect textBounds = new Rect();
textPaint.getTextBounds(valueText, 0, valueText.length(), textBounds);
float textWidth = textPaint.measureText(valueText);
float textHeight = textBounds.height();
canvas.drawText((value == 0 ? "" : valueText), (row * cellSizePixels + cellSizePixels/2 - textWidth/2 + padding), (col*cellSizePixels + cellSizePixels/2 + thickPaint.getStrokeWidth() + padding), textPaint);
}
}
}
这是视图所在的GameActivity。
public class GameActivity extends AppCompatActivity {
//Controls Buttons
Button[] buttons = new Button[10];
private static final int[] BUTTON_IDS = {
R.id.button1,
R.id.button2,
R.id.button3,
R.id.button4,
R.id.button5,
R.id.button6,
R.id.button7,
R.id.button8,
R.id.button9,
R.id.buttonCancel
};
NumbersOnClickListener numbersOnClickListener;
private Board board;
private SudokuModel sudokuModel;
private SudokuBoardView sudokuBoardView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_game);
/*
* NEW GAME
*
* Board Setup
* */
Intent gameIntent = getIntent();
boolean isNewGame = gameIntent.getBooleanExtra("new game", false);
if (isNewGame) {
board = gameIntent.getParcelableExtra("Board");
sudokuModel = new SudokuModel(board, isNewGame);
sudokuModel.getBoard().printBoard();
sudokuBoardView = findViewById(R.id.sudokuView);
sudokuBoardView.setSudokuModel(sudokuModel);
}
//Controls Setup
numbersOnClickListener = new NumbersOnClickListener();
for (int i = 0; i < 10; i++) {
buttons[i] = findViewById(BUTTON_IDS[i]);
buttons[i].setOnClickListener(numbersOnClickListener);
GridLayout.LayoutParams params = (GridLayout.LayoutParams) buttons[i].getLayoutParams();
params.width = getResources().getDisplayMetrics().widthPixels / 7;
params.height = params.width;
buttons[i].setLayoutParams(params);
}
}
@Override
protected void onPause() {
super.onPause();
}
}
SudokuModel类。
public class SudokuModel {
private Board board;
private boolean isNewGame;
private int selectedRow = -1;
private int selectedCol = -1;
public SudokuModel(Board board, boolean isNewGame) {
this.board = board;
this.isNewGame = isNewGame;
}
public Board getBoard() {
return board;
}
public void setBoard(Board board) {
this.board = board;
}
public boolean isNewGame() {
return isNewGame;
}
public int getSelectedRow() {
return selectedRow;
}
public int getSelectedCol() {
return selectedCol;
}
public void setSelectedRow(int selectedRow) {
this.selectedRow = selectedRow;
}
public void setSelectedCol(int selectedCol) {
this.selectedCol = selectedCol;
}
}
董事会课程。
public class Board implements Parcelable {
private static final int SIZE = 9;
private ArrayList<Cell> cellList = new ArrayList<>();
public Board(ArrayList<Cell> cellList) {
this.cellList = cellList;
}
public ArrayList<Cell> getCellList() {
return cellList;
}
public void setCellList(ArrayList<Cell> cellList) {
this.cellList = cellList;
}
public void printBoard () {
for (Cell cell: cellList) {
System.out.println("Cell " + cell.getRow() + ":" + cell.getCol() + " VALUE: " + cell.getValue());
}
}
protected Board(Parcel in) {
if (in.readByte() == 0x01) {
cellList = new ArrayList<Cell>();
in.readList(cellList, Cell.class.getClassLoader());
} else {
cellList = null;
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
if (cellList == null) {
dest.writeByte((byte) (0x00));
} else {
dest.writeByte((byte) (0x01));
dest.writeList(cellList);
}
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<Board> CREATOR = new Parcelable.Creator<Board>() {
@Override
public Board createFromParcel(Parcel in) {
return new Board(in);
}
@Override
public Board[] newArray(int size) {
return new Board[size];
}
};
}
Cell类。
public class Cell implements Parcelable {
private int row;
private int col;
private int value;
public Cell(int row, int col, int value) {
this.row = row;
this.col = col;
this.value = value;
}
public int getRow() {
return row;
}
public void setRow(int row) {
this.row = row;
}
public int getCol() {
return col;
}
public void setCol(int col) {
this.col = col;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
protected Cell(Parcel in) {
row = in.readInt();
col = in.readInt();
value = in.readInt();
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(row);
dest.writeInt(col);
dest.writeInt(value);
}
@SuppressWarnings("unused")
public static final Parcelable.Creator<Cell> CREATOR = new Parcelable.Creator<Cell>() {
@Override
public Cell createFromParcel(Parcel in) {
return new Cell(in);
}
@Override
public Cell[] newArray(int size) {
return new Cell[size];
}
};
}
在此处生成棋盘并将其传递到游戏活动中。
public class SudokuGenerator implements Response.ErrorListener, Response.Listener<JSONObject> {
private static final String TAG = "SUDOKU_GENERATOR";
private String url = "https://sugoku.herokuapp.com/board?difficulty=";
public int[][] puzzle = new int[9][9];
ArrayList<Cell> generatedPuzzleCells = new ArrayList<>();
private RequestQueue requestQueue;
private Context context;
LoadingDialog loadingDialog;
NewGameErrorDialog newGameErrorDialog;
public SudokuGenerator(Context context) {
requestQueue = Volley.newRequestQueue(context);
this.context = context;
this.loadingDialog = new LoadingDialog((Activity) context);
this.newGameErrorDialog = new NewGameErrorDialog((Activity) context);
}
public int[][] getPuzzle() {
return puzzle;
}
public void setPuzzle(int[][] puzzle) {
this.puzzle = puzzle;
}
public void setDifficulty(int difficulty) {
switch (difficulty){
case Globals.EASY:
url = url.concat("easy");
break;
case Globals.MEDIUM:
url = url.concat("medium");
break;
case Globals.HARD:
url = url.concat("hard");
break;
default:
url = url.concat("random");
break;
}
}
public void puzzleGenerator (int difficulty) {
loadingDialog.startLoadingDialog();
setDifficulty(difficulty);
System.out.println("Set Difficulty");
JsonObjectRequest request = new JsonObjectRequest(Request.Method.GET, url,null,this, this);
requestQueue.add(request);
System.out.println("Made request");
url = "https://sugoku.herokuapp.com/board?difficulty=";
}
@Override
public void onErrorResponse(VolleyError error) {
System.out.println("ERROR Response");
newGameErrorDialog.startErrorDialog();
loadingDialog.dismissDialog();
}
@Override
public void onResponse(JSONObject response) {
System.out.println("Response");
//Check if not empty
if (response.length() == 0){
} //Error Handling
try {
JSONArray board = response.getJSONArray("board");
System.out.println("Board " + board);
for (int i = 0; i < board.length(); i++) {
JSONArray box = board.getJSONArray(i);
for (int j = 0; j < box.length(); j++) {
int k = box.getInt(j);
Cell cell;
if (k == 0) {
cell = new Cell(i, j, k, 0);
} else {
cell = new Cell(i, j, k, 1);
}
Log.d(TAG, "onResponse: GENERATED CELL: " + i +" "+j+" : "+k+" "+cell.isStartingCell());
generatedPuzzleCells.add(cell);
}
}
} catch (JSONException e) {
e.printStackTrace();
}
Board generatedBoard = new Board(generatedPuzzleCells);
generatedBoard.printBoard();
loadingDialog.dismissDialog();
Intent gameIntent = new Intent(context, GameActivity.class);
gameIntent.putExtra("Board", generatedBoard);
gameIntent.putExtra("new game",true);
context.startActivity(gameIntent);
}
}
下面是两个截图,分别是新游戏第一次点击时发生的情况(应该是这样)以及返回主活动(新游戏按钮所在的位置)并再次按下该按钮之后发生的情况。