I have a VideoView playing a video whose shape is not rectangular, (i.e. a rotating cylinder with rounded corners). The videoview is displayed within a LinearLayout that has a background colour. I would like the background of the videoview to be transparent in order to give the effect that the cylinder is rotating on top of the background colour without any black corners.
This is what I get:
and this is what I want to get:
Of course, you could ask, why don't I just set the background colour of the video to match the background colour of the container, but the reason I want to achieve this is because my next step is to have an image or a pattern as the background of the container. My layout xml is the following:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#00aaff"
android:orientation="vertical" >
<VideoView
android:id="#+id/surface_view"
android:layout_width="254dp"
android:layout_height="200px" />
</LinearLayout>
While experimenting, I tried to set a background to the videoview, but that had as a result to obscure the videoview entirely.
Thank you.
VideoView is opening a separate Window above the current one. This is because it is based on the SurfaceView. And we cannot set alpha or perform animations with it because it is not syncronized with your other UI elements.
So:
You should use a video player based on TextureView and animate transparent background by "set alpha" to TextureView
You can use these libraries and get a Video Player based on TextureView
https://github.com/Danylo2006/VideoList
https://github.com/sprylab/texturevideoview
Related
Clearly using a background shape doesnt work in the case of VideoView
Also, there are lots of articles how to override onDraw for ImageView and make its corners round.
But how do I do it for a VideoView?
Transparent rounded corners cannot be done with a VideoView or any SurfaceView, as according to the documentation:
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.
With a TextureView it seems theoretically possible, as its supposed to behave like a normal view. However I was unable too: Tried Porter Duff modes of both the TextureView layer paint and a ShapeDrawable in the foreground of the parent FrameLayout.
With a VideoView, what you can do is make corners of a solid color. Use a 9-patch with transparent content and just the corners of a solid color and set in on an ImageView that gets drawn on top.
Edit: Check this example project.
You can easily achieve this effect by putting a TextureView inside a CardView (from the support library).
You can then set corner radius and shadow on the CardView:
<androidx.cardview.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="12dp">
<TextureView
android:id="#+id/video"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</androidx.cardview.widget.CardView>
I think there is no easy way to do this. You could try this for example:
place a video window under a ImageView window
populate the ImageView with a solid color PNG that has a transparent shape in it
use a FrameLayout or RelativeLayout to hold the two views as they allow views to overlap each other easily
I have an image like this used as background in a RelativeLayout:
This image is used as background for all the levels of my game. Every level is drawn onto the blue area.
I want to keep fixed the aspect-ratio of the blue area, changing the size of the red edges to avoid to show to the user unused pixels of their screen. The green area must be fixed to 80dp for all phones. Then I must add a View (a GLSurfaceView) in my layout in such a way that it fit perfectly the blue area. Thus all levels of my Android game will be perfectly the same in all Android device.
How can I solve this problem?
The real image that I use is a little more complex. You can look it here:
Real image
I would use a FrameLayout for the middle part of the screen(blue), add an ImageView, containing the BackgroundImage you want to display, and put the GLSurfaceView on top of it.
Since the aspect ratio is always the same, you could set the ImageViews sclaing to fit xy and the image should always look the same.
Lets assume you are using a simple SurfaceView, the xml code id use to put a ImageView begind it would look like this
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ImageView
android:layout_height="match_parent"
android:layout_width="match_parent"/>
<SurfaceView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
As i dont know how you build your View i cant post the code that does the job, but just add a FrameLayout instead of your GLSurfaceView to your View, with the Same Dimensions, the GLSurfaceView would have.
To that FrameLayout first add the ImageView, then the GLSurfaceView. Both with height and width set to match_parent.
To Figure out the size of your SurfaceView...
Retrieve Display Dimensions
Substract Green Bar Dimensions
Calculate the size of the Blue View, get the Height/Width (whatever is bigger) calculate the missing Dimension
Set the Red Views to Occupie the empty space.
So you would have to do this programmatically :)
I'm developing an app that shows a camera preview on a SurfaceView but I only want to show the top half of the preview.
Is there a way of cropping/clipping the view or will I have to resort to obscuring the bottom half with something like an image,other view or drawing?
regards
Simon
I am currently using this method to do the cropping (basically using the clip child ability of an absolute layout to clip a surfaceview child)
<AbsoluteLayout android:clipChildren="true" android:layout_alignParentRight="true" android:layout_width="240dp" android:id="#+id/absoluteLayout1" android:layout_height="80dp">
<SurfaceView android:id="#+id/swSurfaceView" android:layout_width="240dp" android:layout_height="160dp" android:visibility="visible"></SurfaceView>
</AbsoluteLayout>
Overlaying the SurfaceView with another view is the easiest way to do it... however, it's quite ugly if you ask me.
Why don't just set the SurfaceView height manually? Make it take the 50% of the screen space and it will do what you want. You don't provide code so we'll have to do some guesses: let's suppose you have a LinearLayout, then inside it you put two views: your surface view and another kind of view. Then, you set their height to be 0dip, and their weight to be 1... that should do it.
I'm trying to make a timeout gauge bar animation effect:
The width of a lengthy colorful bitmap image is decreasing, but not x-scaling.
so the image looks not changing and the visible area shrinks.
I couldn't find the sole ImageView clipping or masking support in android.
And I managed to get the clipping effect by surrounding the ImageView in ViewGroup like:
<FrameLayout android:id="#+id/shrink_box" ...>
<ImageView android:src="#drawable/still_image" ...>
</FrameLayout>
then changing the shrink_box's width will clip the portion of the still_image.
But I failed to change the width of the view smoothly.
I tried to change the LayoutParam.width in applyTransformation() but got an Exception, it seems not allowed.
How can I make an Animation that changes the width of the view. OR is there a proper method to achieve the above effect?
You are trying to reinvent the wheel here, just use a ProgressBar and set the progress drawable to your image.
In your xml layout give the ProgressBar this style to make it an actual bar rather than a wheel
style="#android:style/Widget.ProgressBar.Horizontal"
I have an application with a SurfaceView and a MapView. They are displayed in a single view, like so:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/mainlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<com.google.android.maps.MapView
android:id="#+id/mapview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:clickable="true"
android:apiKey="XXXXXXXXredactedXXXXXXXXXXXXx"
/>
<class.that.extends.SurfaceView
android:id="#+id/surfaceview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#00000000"
/>
</RelativeLayout>
Note the MapView comes before the SurfaceView. Because of this, the MapView is drawn "under" the SurfaceView, and all that I see is a black background, with the things that I draw on the SurfaceView showing. If I swap the order, and put SurfaceView first in the file and MapView second, the MapView is drawn, with none of the SurfaceView showing.
According to the SurfaceView Javadoc:
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. The view hierarchy will take care of correctly compositing with the Surface any siblings of the SurfaceView that would normally appear on top of it.
To me, this means that I should be able to put the SurfaceView first in the file, and have it "punch through" the MapView and display what it has. But, as it is, they seem to be two views, and only one is visible at a time.
After thought: I tried setting the background to #00000000 so that the alpha of the background would be zero (i.e. transparent), but it doesn't have any effect.
The alpha setting alone won't really help in this case.
When you setup your views, set the PixelFormat of the view's SurfaceHolder:
glsView = (GLSurfaceView) findViewById(R.id.surfaceview);
glsView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
I ended up abandoning SurfaceView, despite it's wonderful features for drawing smoothly. Now I'm just using a regular old View, overriding its onDraw method. The MapView underneath is currently being refreshed every time this new View is drawn, but I'm looking in to using the drawing cache feature of Views to simplify that.