I'm writing an app for android and I have a class setup that extends View. Inside that class I'm overwriting onDraw.
I have another class where I'm doing a lot of the processing. I was wondering if there was a way I can use the onDraw method inside the 2nd class too? The 2nd class isn't extending anything.
You can instantiate the 2nd class from the first, then pass the Canvas you receive as parameter to the method of the 2nd witch need it.
Something like.
public void onDraw(Canvas canvas){
super.onDraw(canvas);
MyDrawer drawer = new MyDrawer(); //The 2nd class
canvas.store(); //Use it to store the actual matrix and any further change you can do in the paint method will not take effect over the original matrix
drawer.drawOn(canvas);
canvas.restore();//Return the original matrix, any new paint will use the original matrix
}
Related
I am making a 2d game with Canvas in Android.
I have read the documentation of Canvas and I find out that we can create a class that extends View class, like this:
Class MyDraw extends View{
}
and use it as setContentView() in another class, like this:
class HomeActivity extends AppCompatActivity{
void onCreate(Bundle savedInstanceState) {
setContentView(new MyDraw());
}
So my question is: What is the difference between upper code and use MyDraw class as an object without setContentView(new MyDraw()), like this:
class HomeActivity extends AppCompatActivity{
void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_home));
MyDraw myDraw = new MyDraw(context);
myDraw.draw()
}
Which one is better performance?
And when we should use which one?
Performance will be the same here, but there is a very important difference.
If you want to show your canvas, then you need to get it into the content view, so either as the top level view or as a child of it. But in your two examples, only the first one would be shown.
Game engine will be better for performance :)
But, If you want to make it by youself consider using at least SurfaceView https://developer.android.com/reference/android/view/SurfaceView because It provides async drawing to Canvas.
Or you may want to draw it using OpenGL via GLSurfaceView, but this is completely different story
I am creating a finger paint touch mechanism, and I am looking for ways to increase and enhance the performance of the drawing (make it fast and responsive).
In android to draw using canvas we basically create a custom view, we extend the (View) class, and finally we override the most important method to draw and that is the (onDraw) method. We could visualize the usual code for drawing on canvas to be like that:
Usual Drawing
public class UsualDraw extends View{
//constructor (usually 3)
//........
//the onDraw function
#override
protected void onDraw(Canvas canvas){
//here we draw what ever we want
}
}
First Notice
I noticed that others use another technique to draw on canvas, and that involves multi-threading, and instead of extending (View) they extend (SurfaceView). Could be like that:
public class AnotherDraw extends SurfaceView implements SurfaceHolder.Callback{
//constructor (usually 3)
//........
//the onDraw function
#override
protected void onDraw(Canvas canvas){
//here we draw what ever we want
}
//in addition to 3 methods
#override
protected void surfaceChanged(......){
//...
}
#override
protected void surfaceCreated(......){
//here background thread starts.
}
#override
protected void surfaceDestroyed(......){
//here back ground thread should stop.
}
}
basically its a drawing on the background thread.
Second Notice
I noticed that while touch and drawing on the screen, there is missing points which means when you draw very fast then the screen won't keep up with your finger speed (so there is missing touch points or maybe ignored touch points).
My question
1) Why some documentation extend View and others extend SurfaceView? What should I use in my case for responsive drawing? Does it make any difference?
2) What should I do to make the screen keep up with very fast drawing, and make sure that every path is drawn?
I am going crazy trying to figure this out. I am trying to make an array or arraylist of Rect (rectangles) that I can update the coordinates and draw on the screen(to make them move).
Right now I have a separate class called Fire in which I make a new rectangle each iteration with the new coordinates in its own onDraw() method. In the View's onDraw() method's first iteration I add a new Fire to an arraylist.
In the Fire class I have:
public void onDraw(Canvas canvas){
moveF();
Rect r = new Rect(_l,_t,_r,_b);
canvas.drawRect(r, paint);
}
In the View class I have:
protected void onDraw(Canvas canvas) {
int i = 0;
canvas.drawColor(Color.WHITE);
if(i==0){
fires.add(new Fire(20,100,40,120));
i++;
}
for(Fire fire : fires){
fire.onDraw(canvas);
}
}
I got rid of pointless parts of code, but this is the important stuff. The Rectangle prints, however it prints all the previous locations as well and I don't understand why. I have been trying to fix this forever and any help you guys could give would be greatly appreciated. I was able to implement this in java easy, but android is giving me problems.
Thanks in advance!!!
From the code, you are adding new rectangles to the list, and then drawing each rectangle. But from the description, it seems that you just want to draw a single rectangle, with updated coordinates.
Instead of creating a new Rect each time, reuse a rectangle and update its coordinates with set(...).
A second problem is that you set i=0 and then immediately check for i==0, which would be always true. Try something like this instead:
static final Rect rect = new Rect();
// your code here
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
moveF();
rect.set(_l,_t,_r,_b);
canvas.drawRect(rect, paint);
}
With each call to View.onDraw you create a new fire and add it to your list.
Then you iterate over all fires and draw them.
So you get more and more fires.
Do all fires move the same way or is there some random component?
It might be that you don't see the previous locations of one fire, but that there are many fires moving on the same path.
Do you want to have 1 fire moving around or more and more fires moving around independently?
I split my inner View class from my Main class into its own file. In my main class, I have the view set as an onTouchListener which records user movement into a matrix so it can translate and scale the view. After separating it everything works but im unsure how to pass the matrix to the View for onDraw to update. Any suggestions? Thanks
I can think of two ways to do this:
You could create a variable for your matrix in your View class and a method that accepts a matrix as argument and that updates the var with this matrix value. Then you can call this method from your main Activity before calling your onDraw() method, which can then use this internal var for its calculations and so on.
An alternative would be for your matrix var in your main class to be static so you can call it from your View without needing to have an instance of your main class accessible within your View class.
The latter method is the best as it doesn't require your app to maintain two vars with essentially the same value but the former method might be easier to implement, depending on how your matrix is calculated/implemented.
I have a complex custom view - photo collage.
What is observed is whenever any UI interaction happens, the view is redrawn.
How can I avoid complete redrawing (for example, use a cached UI) of the view specially when I click the "back" button to go back to previous activity because that also causes redrawing of the view.
While exploring the API and web, I found a method - getDrawingCache() - but don't know how to use it effectively.
How do I use it effectively?
I've had other issues with Custom Views that I outline here.
I found a better way than using getDrawingCache.
In the method onDraw, apart from drawing in the natural canvas, I also draw on an memory-only canvas.
Bitmap cacheBmp = Bitmap.Create(....);
Canvas cacheCanvas = new Canvas(cacheBmp);
void onDraw(Canvas c)
{
if(updateDueToInteraction)
{
c.drawXXX(...);
cacheCanvas.drawXXX(...);
} else
{
c.drawBitmap(cacheBmp, 0, 0);
}
}
First of all you will have to use the setDrawingCacheEnabled(true) method, so that you're View is cache-enabled. Then, you can use the getDrawingCache(boolean) method which returns a Bitmap representing the View. Then, you can draw that bitmap manually.
If you don't enable caching by calling the setDrawingCacheEnabled(true) method, you will have to call buildDrawingCache() before (and call destroyDrawingCache() when you're done).
Bye!