Android: View embedded in layout. onDraw() method triggered but the screen not update immediately

233 views Asked by At

I am new on Android. I am working on simple Sudoku solver and I have problem with my view. My SolverView contain on Custom View embedded into a layout that contains 2 buttons. When I click on a cell of sudoku grid, a keypad dialog appear that allow me to choose the number for that cell. However, after click on a number on keypad, my sudoku grid not display it immediately although the onDraw() method was called. Instead, it only update on the next time I touch screen. Following is the code

public class SolverView extends View{

private String TAG = "Solver View";
private int size;
private Solver solver; 
private static int selU, selV;

public SolverView(Context context) {
    super(context);
    this.solver = (Solver) context;
    setFocusable(true);
    setFocusableInTouchMode(true);
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

public SolverView(Context context, AttributeSet attrs) {
    super(context, attrs);
    this.solver = (Solver) context;
    setFocusable(true);
    setFocusableInTouchMode(true);
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
public SolverView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    this.solver = (Solver) context;
    setFocusable(true);
    setFocusableInTouchMode(true);
    setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}   

public int getBoardSize() {
    int height = getHeight();
    int width = getWidth();
    return Math.min(height, width);
}

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    size = getBoardSize();
    int cellSize = size / 9;

    Paint light = new Paint();
    light.setColor(getResources().getColor(R.color.puzzle_light));

    Paint dark = new Paint();
    dark.setColor(getResources().getColor(R.color.puzzle_dark));
    dark.setTypeface(Typeface.DEFAULT_BOLD);

    for (int i = 0; i <= 9; i++) {
        canvas.drawLine(i * cellSize, 0, i * cellSize, size, light);
        if (i % 3 == 0) 
            canvas.drawLine(i * cellSize, 0, i * cellSize, size, dark);
    }


    for (int i = 0; i <= 9; i++) {
        canvas.drawLine(0, i * cellSize, size, i * cellSize, light);
        if (i % 3 == 0)
            canvas.drawLine(0, i * cellSize, size, i * cellSize, dark);
    }
    Paint foreground = new Paint(Paint.ANTI_ALIAS_FLAG);
    foreground.setColor(getResources().getColor(R.color.puzzle_dark));
    foreground.setStyle(Style.FILL);
    foreground.setTextSize(cellSize * 0.75f);
    foreground.setTextAlign(Paint.Align.CENTER);
    FontMetrics fm = foreground.getFontMetrics();
    float x = cellSize / 2 - (fm.ascent + fm.descent) / 2;
    float y = cellSize / 2 ;
    for (int i = 0; i < 9; i++) {
        for (int j = 0; j < 9; j++) {
            canvas.drawText(this.solver.getCellString(i, j), j * cellSize + y, i * cellSize + x, foreground);
        }
    }

}

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (event.getAction() != MotionEvent.ACTION_DOWN)
        return super.onTouchEvent(event);
    int cellSize = size / 9;
    int i = (int)event.getY() / cellSize;
    int j = (int)event.getX() / cellSize;
    if (i < 0 || i > 8 || j < 0 || j > 8) 
        return false;
    this.selU = i;
    this.selV = j;
    Log.d(TAG, "onTouchEvent: " + selU + " , " + selV);
    this.solver.showKeypad(i, j);
    invalidate();
    return true;
}

public void setCell(int t) {
    Log.d(TAG, "in setCell: t = " + t);
    Log.d(TAG, "in setCell: selU = " + selU);
    Log.d(TAG, "in setCell: selV = " + selV);
    if (solver.setCellIfValid(selU, selV, t)) {
        Log.d(TAG, "setCell: going to invalidate()");
        Log.d(TAG, "setCell: value change: " + solver.a[selU][selV]);
        invalidate();
    }

}

}

And this is the structure of layout:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/zero"
android:paddingLeft="@dimen/zero"
android:paddingRight="@dimen/zero"
android:paddingTop="@dimen/zero"
tools:context="com.trungkienioicamp.helloworld.Solver" >

<com.trungkienioicamp.helloworld.SolverView
    android:id="@+id/board"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:layout_alignParentLeft="true"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true" />

<Button
    android:id="@+id/clear"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_marginBottom="74dp"
    android:layout_marginLeft="29dp"
    android:text="Clear" />

<Button
    android:id="@+id/solve"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_alignBaseline="@+id/clear"
    android:layout_alignBottom="@+id/clear"
    android:layout_alignParentRight="true"
    android:layout_marginRight="61dp"
    android:text="Solve" />

Can anyone suggest me the solution for this one? Thank for reading

UPDATED: The problem gone when I set the content view of main activity as solverView instance

setContentView(solverView);

But it will not work when I set the content view as a layout

setContentView(R.layout.activity_solver);
1

There are 1 answers

4
Blaze Tama On

Instead, it only update on the next time I touch screen

Try to call invalidate your instance of SolverView after click on a number on keypad.