I have a FrameLayout containing first a SurfaceView, and second a RelativeLayout which in turn contians various Buttons and TextViews.
Upon the canvas of the SurfaceView I am drawing numerous Bitmaps, and, via Touch and Motion Events am allowing the user to drag them around.
These Bitmaps, when dragged around pass underneath the Buttons etc that are inside the RelativeLayout.
Now, it's my (possibly mistaken) understanding that the "Z-level" of the SurfaceView, or whatever it has that passes for it, is entirely unrelated to the actual Z-level of the rest of the Layout. Is this the case? If so, how may I get around it, so that dragged Bitmaps are drawn ontop of other Views? Or what other way can I implement a full-screen canvas and yet not have my buttons etc act like the controls of an overlay.
I guess what I actually need is an underlay, where touch events can still be picked up by the Buttons etc underneath. But I don't know how to achieve this, as, when redrawing my Canvas, I have to also redraw the background.
Can I swap the order of the RelativeLayout and the SurfaceView inside the FrameLayout, and then make the background of the Canvas transparent? If so how? Will touch events still "fall through" to the buttons underneath?
Thanks for bearing with me, I know I'm a bit of a waffler.
SurfaceView doesn't work that way.
SurfaceView has two parts, the "view" part and the "surface" part. The "view" part is a transparent hole that is laid out with the other view elements, and composited onto the view layer. The "surface" part is a completely separate layer that will be positioned and scaled to match the "view" part, and composited by the system compositor rather than the app.
You can control the Z-order of the "surface" layer when the SurfaceView is first created, but it's going to be above or below all View elements. It can't go above some Views and below others because they're completely independent layers. The "surface" layer does not catch input events, so having it on top (via SurfaceView#setZOrderOnTop()) doesn't affect input focus.
For API 14+, you can use a TextureView, which behaves in a more View-friendly way.
Edit: for full details, see the much longer explanation.
Can you clarify a little bit more? In your SurfaceView do you have a background assigned? If not, you could probably also use AbsoluteView if your intention is to simply drag pieces around. If there is no background, you should be able to place the entire view above the RelativeView that you have and only have the various Buttons and such drawn on the view on top, which would be draggable and remain above everything else.
Related
How can I draw (bitmap, line, etc) outside the bounds of a view? From the view's onDraw(), I've read this is not possible as everything drawn will get clipped to the view's bounds.
I did come up with one solution but I'm hoping there's a better one. What does work is to create a transparent view that is at the top of the z order and includes the area I want to draw in (the entire app client area). Then, whenever I want to draw outside some child view, I can simply translate to the coordinates to the transparent view and draw there.
I also read about SurfaceView hoping that would do what I want. But I think it's main purpose is to provide drawing in a separate thread and doesn't solve the problem I'm discussing.
To be clear, it isn't sufficient to simply draw in the parent of the target view because other views in the parent will be higher in the z order and hide the drawing.
Intuition tells me there's a "right way" to do this. Anyone know?
I'm drawing the conclusion that the right way is to do what I proposed - create a transparent view that is at the top of the z-order for the space you need to draw in.
I come to this conclusion after learning how the Navigation Drawer drawing works - exactly in this way. So, if Google uses this technique, I conclude that it's the best way available.
I have a video view. This view is contained inside a custom FrameLayout called VideoStructure, where I can put also a channel logo or things alike.
Under normal conditions, the video is hardware accelerated, so the view is (i suppose) really a transparent "black hole", while the video is decoded & rendered by the relevant hardware.
My question is, if I override draw() in the Video View's container (the VideoStructure extends FrameLayout in the image) to draw some stuff (ie. the circle in the image) OVER the video -I'm overriding draw(), not onDraw()- will this break the hardware acceleration? Can I expect a big performance hit for doing this?
It should have no effect on performance.
SurfaceViews have two parts, the "view" part, and the "surface" part. The "view" part is a transparent hole that fits in with the other views, the "surface" part is a completely independent layer that is composited with the view layer by the system. The video is being sent to the "surface" part.
If you override SurfaceView's "view" renderer, you'll get a hardware-accelerated Canvas for a View that is normally completely transparent (so if you erase it, you better use an alpha of zero and the correct transfer mode).
If you attempt to render on the "surface" part, by getting a Canvas from lockCanvas(), you will either fail (because the video effectively has it locked), or succeed and prevent video from being written to it.
The system compositor is going to have to blend the "view" and "surface" layers no matter what appears in the "view" layer, so making a few more pixels opaque isn't going to have a measurable impact.
Update: see the graphics architecture doc for more details on Surfaces and composition.
I am using a SurfaceView to show a camera preview in my activity.
The SurfaceView is placed inside a fragment.
When this fragment is shown the Surfaceview is punching a hole in my activity,
letting the user to see whatever is behind my activity.
After the camera is fully loaded, everything is fine. But when I want to switch back to another
fragment the same thing happens.
How can I prevent this behavior?
Thanks,
Shuky
SurfaceViews have two parts, the "surface" part and the "view" part.
The "view" part is a transparent hole that gets laid out with all the other views. All of the views are composited onto a single layer. The "surface" part is a completely separate layer that is rendered behind the view layer. It has the same position and size as the "view" part, but appears behind all views.
If you need the "view" interaction to be a bit less weird, and you're using API 14 or later, you can use TextureView for your Camera preview instead.
My idea is to have two surfaceViews. One surfaceView which will hold an image (say ImageSurgaceView) and second surface that lie on top of the first one which holds the annotations (say AnnotationSurfaceView) like circle, rectangle etc. Now I have to map these surface views such that the height, width are same and moreover, both the surface view should move on drag i.e share the touch events. To be precise, when I move the image up the annotations should also move up.
Now, I am not sure if this is possible in android. Can any one tell or share some info on this. I don't have any implementation idea to this and hence I don't have any specific code. Moreover, I couldn't find anything similar.
Thanks for helping.
Yes, this is possible. You can add both SurfaceViews as children of a FrameLayout. You will also want to call setZOrderMediaOverlay on one or both of your SufaceViews in order to specify how they are layered.
Furthermore, this could be a graphic intensive algorithm you are describing. Consider adding the AndroidManifest.xml application attribute android:hardwareAccelerated="true".
Finally, just set up a custom OnTouchListener to handle drag events. Use MotionEvent.getRawX() and MotionEvent.getRawY() to get the touch point, and use this to manipulate the canvases.
What is the best way to draw circles on a canvas that should have an alpha layer and change sizes? Should I use a View or a Surfaceview? The circles should also be clickable. And it should be smooth transitions when changing color size and position?
Should I put this in a runnable or use invlaidate in onDraw?
I would prefer that something like this also worked smoothly in low-end devices.
Any suggestions? I'm new to this kind of animations in Android.
If you are constantly drawing and taking user input at the same time, I would use a SurfaceView. However, if the only draw changes you plan on making to the circles happen when you touch them, then a simple View onDraw() override would probably do the trick. In the end it will just depend on what all is going on.
The point of the SurfaceView is to have that separate thread for drawing. If what you're doing could be in any way considered "game-like," then go for a SurfaceView; otherwise, stick with a View.
I say this because I'm currently working on a project with constant drawing using a View. The shapes that I'm drawing respond to touch and you can scroll through the View while it is still invalidating over and over. All this with a View and it still runs just fine on lower-end devices (I've only gone back to GingerBread, though).
Good luck!
I should also mention that in the project drawing in a View, almost everything has various alpha values and what not and runs fine.