I am attempting to build an augmented reality application for Android and have come across the problem of layering surface views. I need a surface view to display the camera preview onto which I will overlay graphics, and I need a surface view to draw my graphics on. This second surface also needs to be drawn above the camera preview but have a transparent background. In my current implementation, I have both surface views working and appearing as they are supposed to, but the background is not transparent and therefore there is no appearance of the second surface view with the graphics drawn being superimposed on the camera preview surface view. How could this be achieved? Upon searching numerous stack overflow questions as well as other forums I've come across many conflicting opinions pertaining to this matter. Some say that layering surface views in Android is impossible whilst others say that it is a matter of using a different layout (FrameLayout vs. LinearLayout?) Specifically, my implementation includes two views: a class, CustomCameraView, that extends SurfaceView, and a class, CustomDrawView, that also extends SurfaceView contained in a FrameLayout with the CustomDrawView appearing after the CustomCameraView. How can these be layered so that CustomDrawView seems superimposed on CustomCameraView?
I think a lot of people have tried this. A Google Enginee stated (here) clearly, that you should avoid stacking Surface Views. Even if somebody has found some trick to do it, it is probably incompatible and will lead to problems.
I think this gives three options, depending on your requirements:
View(s) on Top of Surface View
Use a Surface View for the Camera preview and stack Views on top of it. The disadvantage of this approach is that drawing on "normal" Views a) is slower and b) takes place in the UI thread. You can get around b) if you implement the threads yourself. But generally, that is probably the way to go if your overlays contain something like UI elements or a few Drawables that don't need to be updated too often.
Do everything in a SurfaceView
This will give yo better performance and less overhead during runtime. You have just one SurfaceView. Composite the overlays on your SurfaceView and and draw everything there. Of course, you can combine both approaches.
Do everything in a GLSurfaceView
This is probably the way to go for real performance. Like above, but with the camera view rendering to a OpenGL texture in a GLSurfaceView.
I got this working having 2 transparent views above the camera's SurfaceView using the following approach:
My activity sets up all its views in the onCreate() method, I make no use of any layout file for that. It looks as follows:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null); //savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
cameraPreview = new CameraPreview(this);
addContentView(cameraPreview, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
animationView = new AnimationView(this);
addContentView(animationView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
crosslinesView = new CrosslinesView(this);
addContentView(crosslinesView, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
}
cameraPreview is of type SurfaceView, animationView and crosslinesViews are of type View. The onDraw() of the 2 latter views looks as follows:
protected void onDraw(Canvas canvas) {
// Have the view being transparent
canvas.drawARGB(0, 0, 0, 0);
// Your drawing code goes here
// ...
}
Good luck!
Related
Good day to you all, I am creating a ride app and I was asking for some assistance in the following problem I am facing.
So, On the image below the grey background represents a google map fragment and above it sits two views(black) I wanted to know if it were possible to only show a polyline and markers between the black views only in the red area and have the rest of the map showing in the background as well.
If it helps I have managed to get the LatLng's of the corners of the red box using:
googleMap.getProjection().fromScreenLocation();
Thank you in advance!
Yes, it is possible. Several ways. For example, the red area of your figure can be View (e.g. custom view) with transparent background and you can draw your polylines on it (you need to take into account position of transparent "red" view on map view for correction of fromScreenLocation()/toScreenLocation() methods results). Also, probably, you can use two MapViews one over another and synchronize its scrolling and zooming, but IMHO best way is to to implement custom view component based on MapVew (or MapFragment) an override onDraw() for MapVew-based (or dispatchDraw() for MapFragment-based) method like in this or that answers:
..
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
drawPolylinesInRegion(canvas);
canvas.restore();
}
...
In drawPolylinesInRegion(canvas); method you should draw your polylines and markers "manually" converting coordinates of them via method opposite you mentioned: toScreenLocation() and taking into account size of "gray regions" of you example figure.
Goal: A highlighted section of an image (the image covers the whole screen). The rest of the screen needs to be faded out.
Example
So far I've got the fading working using the foreground of a FrameLayout and placing the image as the background of a RelativeLayout within the FrameLayout. The solution I'm thinking is that I need to create 2 Drawables and merge them into one that FrameLayout Foreground can consume.
I've also been reading a bit up on PorterDuff, but I think that may be overkill for what I'm trying to achieve.
The fade functionality is working fine, but the source of the fade with transparent section is not.
I suggest that you have the original image in an ImageView on top of it place 4 views which are partially dimmed and that's it!
With some basic math you can know the sizes for each view, and using RelativeLayout will allow you to easily place them on the screen.
Good Luck!
P.S. I've attached a sketch to illustrate what I'm suggesting.
So, I'm working on a main menu activity for my android application.
I want to create background animation where there are things translating from the top of the screen to the bottom. The x position and translation speed of each will be random (within some limits).
I have created a new thread to run this animation (so the UI doesn't get slow or messed up).
I do not want to use a SurfaceView if possible. I'm planning on using an ImageView resource, then using .startAnimation(animation), where animation is a translational animation resource.
My problem:
Is it possible for me to create multiple instances of the same ImageView, if I wanted to run multiple animations at the same time (3 of the same ImageViews falling at different rates and different x positions)?
How do I set the starting point of each of the ImageViews to be at some specific x position? For me to specify an absolute starting point, which type of layout would be required?
Any help is appreciated.
I think I've just decided that a linear layout placed on top of a surface view is the best option. The animation would just be drawn on the surface view while the regular menu interface is contained in the linear layout.
Update:
Used a FrameLayout with a SurfaceView and LinearLayout inside. It works perfectly.
Actually, the subject is a question.
I want to draw on top of the map a view as overlay, simply my view consist of linear layout with 9patch background and two textview inside. I need to draw those layouts in runtime and they will be linked to geo location
There is no problems to define such view, but it is problematic to create an overlay that will handle such draw...
Yes - this is what a FrameLayout is for! Children in a FrameLayout appear on top of each other, with the last item displayed on top and the first item displayed on the bottom.
Put your MapView as the first child of a FrameLayout and your LinearLayout as the second.
Actually there is no way to do what I want, I've found a way to convert any layout to bitmap, but firstly you need to invoke layout on the root view and define it boundaries, so in my case it is the same to simple drawing on canvas which I've used for my solution. Converting layouts to bitmap is a good thing when your layout is already drawen on the screen, but when you need to draw layout on the canvas from scratch there is no benefits due to simple drawing on canvas.
You could create a drawable out of your view by converting it to a bitmap.
Or you can try to use this. Has the same effect: https://github.com/jgilfelt/android-mapviewballoons#readme
And you can modify it like you want to show whatever view you like
Is there a possibility to add a view or derivative (button, textview, imageview etc...) to another view without having to go through layouts?
I have a class called ScreenView, it derives from View (e.g. public class ScreenView extends View).
I wanted to display text into it, labels, images etc..
On an iPhone it's trivial, simply create my objects and use addSubview method ; you can embed any UI objects into another. Most UI toolkits work that way too.
Problem with layouts is that I haven't found an easy way to properly position a subview (say a text view) in a given location of the enclosing View. I want one to contain the other...
I was hoping I had missed something in the documentation (which is far from being intuitive that's for sure) and I could do something like myView.addView(subview). But it ain't so :)
As a side question, what is the closest to iPhone's UILabel in the Android world?
A UILabel can contain a text or a graphic. Right now I've been using TextView and ImageView but they aren't anywhere as flexible when it comes to layout as a UILabel
Edit: Making my View inherit from ViewGoup instead, let me add subview..
However, I want to draw in my view. I found that when ScreenView extends ViewGroup, the onDraw function is never called then.
Something like:
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
// make the entire canvas yellow
paint.setColor(Color.YELLOW);
canvas.drawPaint(paint);
}
Would paint in yellow my view if ScreenView extends View ; but not if it extends ViewGroup.
How do you draw directly in the view then?
Thanks
JY
Use a ViewGroup, that's what they are for. And then you can call addView() :)
After making my class inherit from RelativeLayout instead, it does draw my subviews.
GroupView doesn't draw anything by default, and onLayout needs to be fully written. With no documentation on this matter it's going to be a hard thing to do.
onDraw isn't called by default, it does get called if you set the background colour or add any drawable item.
Otherwise you need to draw during dispatchDraw instead.