I have an application that uses SurfaceView do draw content. I wanted to add nice ShowcaseView library to my application which uses getWindow().getDecorView()).addView(...) to draw itself on top of other views and decorations. But in my case it does not draw over my SurfaceView (if I remove it from layout, everything works perfect).
Is it a limitation of Android architecture, or I can tune something in my SurfaceView or fix something in ShowcaseView library?
Update
If I call mySurfaceView.setVisibility(View.INVISIBLE) just before creating ShowcaseView everything works perfect too (except that my main view area is black).
Update 2
I've read about Z-indexes of SurfaceView in documentation. I do not touch them in my code.
SOLUTION
Add setWillNotDraw(false) after calling the super constructor of your SurfaceView.
Other hints regarding surfaceview
It might be helpful to
add the SurfaceView to a Container -e.g. RelativeLayout
call getWindow().getDecorView()).requestTransparentRegion(mySurfaceView); after making your view visible
Related
I have a GLSurfaceView that has the setZOrderOnTop set to true (otherwise the GLSurfaceView does not display the content correctly). I need to display a Fragment on top of this view but it seems an impossible task. I've tried everything present on the internet and nothing works.. Thanks in advance!
The SurfaceView's surface is on a separate layer from all of the View UI. By default, it's below the View layer, but if you use setZOrderOnTop() then it appears on top of everything.
You didn't say what sort of layout you're trying to get, but it's likely that a TextureView will work better, as those are rendered on the View layer.
You can use GLES to render to a TextureView, but you won't have the EGL setup or thread handling that GLSurfaceView provides. See Grafika for examples (e.g. "Simple GL in TextureView").
I am creating a layout of type FrameLayout, in which I am adding two views. Two views are objects of GLSurfaceView and SurfaceView respectively. According to Android Developers Documentation regarding SurfaceView,
"The surface is Z ordered so that it is behind the window holding its SurfaceView; the SurfaceView punches a hole in its window to allow its surface to be displayed."
It works well for me and SurfaceView always stays behind my GLSurfaceView (used for opneGL drawings). But resuming after external event the behavior is odd for a following configuration,
Android Version: 4.3
Device Model Number : Nexus 7
Kernel Version 3.4.0.g1f57c39
Jun 13
Build Number: JWR66N
For this configuration, resuming after external event puts my GLSurfaceView behind SurfaceView. In other words, SurfaceView is placed at top in ZOrder and my OpenGL drawings are no more visible. On versions greater that Android 4.3, this behavior is not seen.
I can replicate this behavior on all versions by calling SurfaceView's following method with true as a parameter.
void setZOrderOnTop
Is this known issue. Anybody can help me on this?
Regards,
Sumedh
SurfaceViews have two parts, the Surface and the View. The Surface is a completely independent layer. The View is there so the UI layout code has something to work with. Generally the View is just transparent black, so you can see through to whatever is behind it.
GLSurfaceView is just SurfaceView with some code to manage EGL contexts and threading. Underneath it's just a SurfaceView. So if you have both a SurfaceView and a GLSurfaceView, and they have the same dimensions and Z-order, then one of them is going to "win" and the other is going to "lose" because they're trying to occupy the same space at the same time. There is no defined value for which one will "win", so inconsistent behavior is expected.
One way to avoid clashes is to leave one set to the default Z, and call setZOrderMediaOverlay() on the other. The "media overlay" is still behind the UI, but above the default Surface position. If you use setZOrderOnTop(), the Surface will be positioned above the UI as well.
The upper Surface will need to be rendered with transparent pixels if you want to see something behind it (the same way that the View needs to be transparent to see the Surface).
The most efficient way to avoid this issue is to not have this issue: use one SurfaceView for everything, rendering all of your non-UI-element content to it. This requires a bit more work (and probably a SurfaceTexture) if you're rendering video or showing a camera preview on one of the Surfaces.
You can find some examples in Grafika. The "multi-surface exerciser" demonstrates three overlapping SurfaceViews rendered in software, overlapping with UI elements. Other activities show ways to work with Surfaces, GLES, the camera, and video.
See also the Android System-Level Graphics Architecture doc, which explains all this in much greater detail.
Dont use "setZOrderOnTop" as true. That will get it over all the other layouts.
If you are using multiple surfaceviews. use this for each surfaceview
yourSurfaceView.setZOrderMediaOverlay(true);
then set this setZOrderOnTop as false for the surfaceview you initiated later and wanted it to get back to the other surfaceviews
secondSurfaceview.setZOrderOnTop(false);
I'm using OpenGL ES on android 2.3.3 at the minute to render a simple 3D game. I'd like to extend it using the built in gestures library, but I can't find a way to recognise the gestures from a GLSurfaceView as opposed to an android view(I don't have an XML layout is what I'm saying)
Is there any way to either implement an XML layout on top of what I have already, or preferably to implement the gestures library on top of the GLSurfaceview instead.
Thanks.
You can attach a normal onTouchListener to GLSurfaceView, so long as you have an instance of GLSurfaceView (which it sounds like is what you have). This is only really useful if you just want to know the raw x,y coordinates on screen where the user has pressed (e.g to rotate around the y if the user moves their finger left/right across the screen)
For gesture library, which I haven't used myself, you should be able to just place your GLSurfaceView inside a frame layout and then place another view (e.g. linear layout set to match_parent) in the same frame layout so that it completely covers the GLSurfaceView and is on top of it. Attach the gesture library to this view (and obviously make sure it is transparent so people can still see the GLSurfaceView below).
The gesture library has a way of 'stealing' events from the view. See here for details.
Here, here, and here are some examples that should make it clearer.
In Android 2.2, I want to display a few sprites and clickable animations over an existing view. I just discovered that SurfaceView cannot be transparent
I tried overriding dispatchDraw() of a LinearLayout but that doesn't seem to be callable via a Runnable Thread.
I also tried to extend Canvas directly, but that quickly turned into a mess when trying to place it in my XML layout.
Do I have to use GLSurfaceView to have a drawing view whose background is transparent?
Optimally, I'd like to just have a Canvas on which I can draw Bitmap at various coordinates, instead of dealing with the details of GL (unless GL is the only way I can do transparency).
Silly Rabbit. Just use Views and move them around wherever you want within a FrameLayout. SurfaceView is not designed for what you're trying to do.
I'm going to try Switching from Canvas to OpenGL and toss in parts of TranslucentGLSurfaceView.
I'm still open to selecting an answer that doesn't require OpenGL, just for the sake of it solving my original question.
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.