I am trying to develop an android application to display a zoom-able, pan-able map, (which is just a bitmap image), that also allows the user to click on certain points on the map.
I am struggling to find the most effective way of implementing such an app. After trying numerous other methods, (including Webviews, OpenLayers), the best way, (according to this site at least), seems to be using a SurfaceView with a Canvas. The code I have so far is pieced together from snippets I found all over the internet, so it just crashes. I have included it here anyway in the hope it gives some idea of what I am trying to achieve:
public class Main extends Activity {
private Bitmap bmp;
private SurfaceView surfaceView;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView)findViewById(R.id.surface);
bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.testmapbmp);
//decode the bitmap file
Canvas canvas = new Canvas(bmp);
//create a canvas from the bitmap, then display it in surfaceview
surfaceView.draw(canvas);
}
}
Is this the best way to achieve the functionality I want for my application? Or is there a better way, especially if I could run into problems later on, implementing the clickable sections of the map, for example.
I really need help from someone who has created something like this before, so I can get my train-of-thought on the problem, but I greatly appreciate any help/pointers/tips at all!
Thanks
Your piece of code is not really correct.
Usualy if you want to do this kind if things you need to create your own custom view (either by inheriting View or SurfaceView). In your View subclass you need to override method onDraw(Canvas) and draw your bitmap on canvas by using one of canvas methods.
To make it pannable and pinch-zoomable you need to use Scroller and ScaleGestureDetector classes. Usually panning or scaling is done by applying affine transformations to a canvas by using it's methods (rotate, scale, translate).
Difference between SurfaceView and View is that in SurfaceView you can draw directly from separate thread, which means you can organize sort of rendering loop there and draw from it. It is good for simple games and animation effects. I believe, for purpose of drawing a bitmap this is overkill and much simpler to subclass View.
I'd start with this and this, if I were you.
Related
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 have this code in a class that extends surface view and implements runnable
I am able to use the class basically allows you to draw to the canvas using different colors and such. I'm trying to get a method that will allow me to save the image after it is drawn and this is the method. No matter what i do i just get a black image with nothing on it. Any ideas?
I have cache drawing enabled
Objective get a bitmap image from a custom SurfaceView I have exhausted options of looking at some other post on here and didn't find anything to work. Here is hoping that there is recently a new solution to this. Many thanks
public Bitmap getImage() {
Bitmap bitmap = Bitmap.createBitmap(this.getWidth(),
this.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
this.draw(canvas);
return bitmap;
}
Your question became clear only by your last comment. In the code that you posted above, you are returning with return bitmap. That will return the local variable bitmap. This local variable is totally blank. You may be drawing to your bitmap or associating an image to it, somewhere else in the code. But the instance of bitmap in your above code, is blank and only local to the function. You cannot expect it to return your updated, latest bitmap.
Now, after your comment I googled "getting a bitmap of current surfaceview" and it led me to this SO answer: Create Bitmap from SurfaceView
In that question, it was apparently solved by extending View instead of SurfaceView. Drawing cache only works for View.
Update: Follow the below tutorials. Based on the code pasted by you, it's not clear what the error is. There are a lot of things that need be done for drawing to SurfaceView, and I'm not sure if you have done those, and I cannot ask for every such missing item. I followed below tutorials for my basic graphics projects. You need to read them and see if you have missed anything.
Tutorials on Canvas drawing:
Playing with Graphics in android all parts.
Android 2D
I Have created a guidance application which consist a map. This map is drawn dynamically using the data from the database.[rectangle coordinates] To draw the map i have used a View class and overriden the Ondraw method.
The problem is that i cant find a way to implement the zoom in functionality. I have already used Gesture Detector class to handle OnLongPress and the OnTouchEvent methods. I was thinking of the Pinch-to-Zoom-in functionality but have no idea of how to do it.
Looking forward for some great ideas. Thank you!
Classes extends
View
GesturDetector
Can you give us some more information about how you are drawing this dynamic map? For now, I'll make an assumption and run with it. If you are drawing shapes on a canvas you can point the canvas at a Bitmap to draw onto:
Bitmap myDynamicMapBitmap = new Bitmap(MAP_WIDTH, MAP_HEIGHT, Bitmap.Config.ARGB_8888);
mapCanvas.setBitmap(myDynamicMapBitmap);
// Draw your map on the canvas here
Now that you have a bitmap representation of your map, you could utilize this open source project, which is basically an adaptation of the built in Android photo gallery app that allows users to pan and zoom images:
ImageViewZoom on GitHub
I've used that project before for an app, and it works really well. You may need to tweak it some to get your desired behavior (for example disabling panning, since you didn't say you wanted that).
Then all you have really have to do is:
imageViewZoomInstance.setImageBitmap(myDynamicMapBitmap);
That view includes built-in pinch zooming. You'll probably want to merge it with your current View that you've created.
I am working on application in which i am drawing a image on the canvas now i want o draw the second image in that canvas.
for example see the image ......
the first image s looking as follow ....
when i click on some place then it will show as follow
but the other thing which is shown in the image (thymin) it should display as fadein in the canvas
how to do it i am not getting any thing can any one help me .....
That's quite complicated by the sounds of it though not impossible to achieve. I think it would take more than the standard View class to achieve this, more like you would need to use the SurfaceView class where you have greater control over what gets drawn and where and when. If you're not familiar with Android 2D graphics then a good place to start would be here.
For drawing the bitmap, you could use canvasObject.drawBitmap() method of Canvas class. drawBitmap takes a paint object as one of its parameters, you could programmatically vary the alpha value of the paint object to create a fade-in effect. Paint class has a setAlpha(value) method to do this. I haven't tried this out myself but this should work.
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.