How do I call onDraw() on my class extending GLSurfaceView. I need the canvas for drawing the gestures of the user. (FingerPaint.java logic). Mean while I need the onDrawFrame() of the renderer to be called for other effects. I can manage the calls to both the methods by maintaing a flag. I am calling invalidate() but that too is not able to call the onDraw(). GLSurfaceView extends View so I thought I can override onDraw() and can call it by calling invalidate(). Please Throw some light. Thanks in Advance Krishna :)
Try calling requestRender () from your GLSurfaceView.
Obviously this works best when setting rendermode to "RENDERMODE_WHEN_DIRTY".
And that means you won't be rendering continuously, so that may interfere with the "constant" rendering required for your effects.
I think the best solution would be to split the rendering up between 2 overlaying surfaces and 2 renderers. Request the bottom surface (fingerpaint surface) to render a frame whenever the user interacts, and on the top one (gfx surface) you render continuously. Or swap this around... whatever works best.
Just call invalidate() and onDraw() will be called, just like normal View. The canvas is drawn on top of the GLES viewport.
So far I couldn't implement invalidate(Rect dirty). The whole view is redrawn always.
It is needed to put setWillNotDraw(false) before drawing.
Related
Okay so far when I have used SurfaceView I would override the draw method and then call it from a seperate thread. However, recently I tried to not override it but simply make all my canvas drawing calls in a custom method, and it worked. I would just do all my drawing the same way but instead of all the code being in overridden draw method, I would just put it all in another method and it worked anyways. So whats the point of overriding anything? I honestly still don't know how all the drawing works behind the scenes as its not explained...
For SurfaceView as you noticed yourself it makes no difference. There's no point of overriding draw and then calling it yourself from the separate thread.
The SurfaceView only have the method there because it inherits it from the View class, but because you're, in a separate thread, acquiring the lock to the canvas, drawing and then releasing, it doesn't matter if you pass it to the draw method, if you use directly on the thread run or some other Runnable
Maybe one could argue that it's more organised (and do never underestimate the importance of a well organised code), but it's not a necessity.
I am a newbie. I make a simple game using Canvas. I wrote almost all the code inside the onDraw() method and there is a lot of calculations there. There is an invalidate() method in the end of onDraw() in my code. That's how I call to redraw my view. How can I redraw only a part of Canvas? The main problem is that I have a lot of calculations inside the onDraw() and it slows the whole game. I tried to use bitmaps like here:
creating a bitmap - stackOverflow
but it didn't resolve the problem because creating a bitmap is too slow process. Is it a good idea to use SurfaceHolder and Callback? I tried to use it but I don't know if it is a right way to do what I want to do. Can anybody help me? How to redraw my view only partially to stop chosen elements always redrawing by new calculations (to drawing them from saved state)? I want to redraw whole view only when it is needed. It would be great if somebody post a code which would resolve this problem (it could be even two rectangles).
use the same bitmap instead of creating a new one, and call invalidate with a rectangle (or with the bounds) as its parameter.
in the onDraw, you can call canvas.getClipBounds() in order to find the rectangle to invlidate.
also, in order to improve your code, try to avoid creating new objects on the onDraw method.
in fact, if it's a heavy game, consider using openGL instead. for simplicity, you can use third party libraries like libGDX or AndEngine.
Try creating the Bitmaps in the Class method and calling them from onDraw().
public class DrawView extends View {
public DrawView(Context context, AttributeSet attributeSet) {
super.DrawView(context attributeSet)
//Create your bitmaps in here
}
}
I used surfaceview to create a graph. This graph changes continuously over time.
When I use postInvalidate method to update graph, surfaceview is redrawn but I don't want to redraw xy-axis. what should I do?
I believe what you are looking for is the lockCanvas(Rect dirty) method from the SurfaceHolder class.
http://developer.android.com/reference/android/view/SurfaceHolder.html
Official documentation:
"Just like lockCanvas() but allows specification of a dirty rectangle. Every pixel within that rectangle must be written; however pixels outside the dirty rectangle will be preserved by the next call to lockCanvas()."
Therefore you can just change the graphs contents, leaving any pre-drawn axis
I have a scrollview that contains a custom view. The custom view is bigger than the area of the screen and draws properly.
The scrollview however tends to call onDraw() non-stop when scrolling, and I can't seem to make it smooth.
I used ScrollView.getDrawingRect() to calculate the visible portion of the screen and only draw to that, but it still returns the entire viewport (so it's optimized to not draw offscreen areas), and not the delta between the last position and the current one. Ideally I'd want to draw only the delta, and not the entire visible window.
If anyone can point me to more information about how to use the drawing caches, and if that will help optimize scrolling, I'd love to implement it, or any other possible solutions it would be greatly appreciated.
When content is scrolled, the entire viewport needs to be redrawn because all of the content has moved. I don't think there's anything that needs to be done to optimize a ScrollView - if scrolling is slow then it's the drawing method of your custom view that is too slow.
Try to avoid object creation in your draw methods which is usually the main culprit for poor drawing performance.
Edit: Also the scrollview could blit the old content up or down quickly that is still drawn on the screen, and then request a redraw of only the "new" portion of the screen. (only applies to opaque views).
I encountered the same problem. I solved it by using the function setDrawingCacheEnabled(true). By enabling this setting, your canvas view will be cached as bitmap, so you don't have to call canvas' draw method each time onDraw() is called.
In your custom view's constructor, you will need something like this:
public CustomView(Context context) {
setDrawingCacheEnabled(true);
drawnFlag = false;
}
In your onDraw method, you will need something like this:
public void onDraw(Canvas canvas) {
if (! drawnFlag) {
canvas.drawPath(...);
canvas.drawPath(...);
drawnFlag = true;
}
}
Now, scrolling on this custom view should be smooth since we only call the drawing methods once.
Afaik the ScrollView sets a proper clip rect on the canvas your view gets in onDraw so you only need to draw what's inside that rect.
You could also implement cache bitmaps based on the clip rect's size.
I'm developing chess game for Android (androidchess.appspot.com). If I want to add animations, should I use custom View extending Canvas (I do this now), or custom View extending SurfaceView?
I haven't tried using a View to extend Canvas, but for my game I'm using the same method as the LunarLander example game:
public class CustomView extends SurfaceView implements SurfaceHolder.Callback
The usefulness of this is that it gives you handles for SurfaceHolder (so you can call up the canvas which is drawn to the screen), and the callbacks for surfaceCreated, surfaceChanged and surfaceDestroyed. That lets you do things like drawing a custom animation as soon as the surface is available or make sure that you don't try to draw to the canvas after it has been deactivated. Looking through LunarLander should show you how to use these properly.
Edit: I remembered another reason why using a SurfaceHolder was useful. This is because, as I mentioned above, it lets you get direct access to the canvas which is drawn to the screen. With a SurfaceHolder this is done not by overriding onDraw but by using something like Canvas canvas = mSurfaceHolder.lockCanvas(). (See LunarLander for exact syntax). The reason this is important is because it lets you control exactly when the drawing happens. If you can only work by overriding onDraw(), then the drawing doesn't happen until your program reaches a 'waiting' phase. In other words, you can't use invalidate() and onDraw() in a loop because the drawing won't happen until the loop finishes. And since you're likely to use loops for things like drawing a piece moving across the screen, this becomes a problem.
Note: It may be possible to avoid this problem by using multiple threads. I simply haven't tried that since it isn't required for my game; the only animation is has is fixed-length animations in response to user input rather than something continuously moving in the background, so I haven't experimented with multiple threads yet.