Monday, March 12, 2012

Draw App


For this week's hand in we have had to develop an application which allows the user to draw on the screen using gestures.
Our application (see the screen shot below) includes several controls for the app, controls like clearing the screen, increase or decrease the size of the dots, selecting the color, draw different shapes (dots, lines, squares and circles) and also controls for undoing and redoing.



The main view of the application consists of a view with a linear layout (with vertical orientation) which nests a draw view as it's first child and the controls as the second child. The reason for using a nested view is purely esthetic, its role being to hold the drawing area on top of the screen and the controls on the bottom.

The drawing is done by using an ArrayList of DrawingElement and than in the onDraw() method just paint all the elements in the ArrayList on the screen.

In order to be able to store all the elements the application uses the onTouch() method together with the actions provides by the event calling this method.

Each DrawingElement contains fields for storing the x and y coordinates when the user touches the screen and x and y coordinates for the case when the user releases the screen (these last two coordinates help in drawing all the figures except for the dots). The element also contains fields for storing the color the element has, its type and also its size (in case of the dots).

After each element is stored the invalidate() method is called in order to tell the AndroidOS to draw every element on the screen.

One could thing is that the user can select the color to draw with by using the color control. This control opens a ColorPickerDialog which changes the value of the color field in the DrawView (the nested view):


It is able to change the value of the color field because the nested view implements the ColorPickerDialog.OnColorChangedListener and than because I have implemented the colorChanged() method required for the listener:

public void colorChanged(int color) {
paint.setColor(color);

}



Another cool thing about the application is that it allows the user to see the size of the shapes he is drawing while dragging on the screen. This is done by implementing the case of MotionEvent.MOTION_MOVE. The code snippet below demonstrates this case:

in the onTouch(View view, MotionEvent event) method:

if (event.getAction() == MotionEvent.ACTION_MOVE) {
if (moveFlag == 1 && elements.size() != 0) {
if (lineFlag == 1 || circleFlag == 1 || squareFlag == 1) {
// remove the element added by the move event
elements.remove(elements.size() - 1);
}

}

// get the end point of the line
element.x2 = event.getX();
element.y2 = event.getY();
element.color = paint.getColor();
element.size = drawSize;
if (dotFlag == 1) {
element.type = 1;
} else if (lineFlag == 1) {
element.type = 2;
} else if (circleFlag == 1) {
element.type = 3;
} else if (squareFlag == 1) {
element.type = 4;
}
// prepare a temporary element to be added to the array of
// drawing elements
DrawingElement tempElement = new DrawingElement();
tempElement.x1 = element.x1;
tempElement.y1 = element.y1;
tempElement.x2 = element.x2;
tempElement.y2 = element.y2;
tempElement.type = element.type;
tempElement.color = element.color;
tempElement.size = element.size;
elements.add(tempElement);

invalidate();
if (moveFlag == 0) {
if (lineFlag == 1 || circleFlag == 1 || squareFlag == 1) {
moveFlag = 1;
}

}

}


One other cool thing for the application is that the user can undo and redo all of his actions. This has been achieved using a stack to push the elements when the user select the undo control and pop the elements when the user selects the redo control.

public boolean onUndoClick() {
if (elements.size() != 0) {
// get the last elements
DrawingElement d = elements.get(elements.size() - 1);
// remove last element from the elements array
elements.remove(elements.size() - 1);
// insert the element in the stack
undoStack.push(d);
invalidate();
// add the action to the log
Log.d(TAG, "Undo: " + d);
}

return true;
}

public boolean onRedoClick() {
if (!undoStack.isEmpty()) {
// get the last element added to the undoStack
DrawingElement d = undoStack.pop();
// add the element to the elements array
elements.add(d);
// draw the screen
invalidate();
// add the action to the log
Log.d(TAG, "Redo: " + d);

}

return true;

}


The application can be downloaded from the link below:
The apk:

The source code:



It took me approximately 10 hours to develop this app. I have spent most of the time dealing with the motion event. The undo and redo controls took me approximately 10 minutes to implement. ;)  

No comments:

Post a Comment