Resize VideoView - android

I am attempting to dynamically set the size of an Android VideoView. I have looked on StackOverflow as well as the internet; and the best solution I found was from here. I have put my implementation below:
public class ResizableVideoView extends VideoView {
public ResizableVideoView(Context c) {
super(c);
}
private int mVideoWidth = 100;
private int mVideoHeight = 100;
public void changeVideoSize(int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
// not sure whether it is useful or not but safe to do so
getHolder().setFixedSize(width, height);
forceLayout();
invalidate(); // very important, so that onMeasure will be triggered
}
public void onMeasure(int specwidth, int specheight) {
Log.i("onMeasure","On Measure has been called");
setMeasuredDimension(mVideoWidth, mVideoHeight);
}
public void onDraw(Canvas c) {
super.onDraw(c);
Log.i("onDraw","Drawing...");
}
}
The video resizes correctly on the Android emulator as well as on a Motorola Droid X; but on a Motorola Droid, the VideoView resizes but the video playing in the VideoView does not resize. On the Motorola Droid, if the VideoView is set to a larger dimension than the video playing, a black background appears in the VideoView with the video playing in the top left corner of the VideoView on top of the black background.
How does one resize a VideoView properly in Android?
Thanks,
Vance

My implementation works like this:
RelativeLayout.LayoutParams videoviewlp = new RelativeLayout.LayoutParams(newwidth, newheight);
videoviewlp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
videoviewlp.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
videoview.setLayoutParams(videoviewlp);
videoview.invalidate();
By invalidating the videoview, you will force it to redraw the whole videoview using the new LayoutParams (and the new dimensions).

Related

ImageView Resizing On Orientation changes

I have a question regarding the process of resizing an ImageView Have on orientation changes.
I have to place a bitmap on the top of an image view. (Basically a marker placed by the user when touching it). On orientation change, I store the relatives position of the marker and intent to restaure it when the image is re-displayed.
for now I do it this way :
on restauration I call this :
handler.post(setCollectedAnswersRunnable);
refering to this :
Runnable setCollectedAnswersRunnable = new Runnable() {
#Override
public void run() {
if (iv.getMeasuredHeight() != 0) {
int x = Math.round(coordinateCollectedAnswer.x * iv.getMeasuredWidth() / (float) question.getImage().getWidth());
int y = Math.round(coordinateCollectedAnswer.y * iv.getMeasuredHeight() / (float) question.getImage().getHeight());
selectedX = x;
selectedY = y;
addPointerImageView(x, y);
} else {
handler.postDelayed(this, 330);
}
}
};
The important thing to note is this works very well when I go from a larger ImageView to a smaller one ie when passing from landscape to portrait.
But in the other way, it doesn't. The ImageView seems to be restaured first with the same size and then scaling up witch mess my marker up. So I certainely could check if it's the same size as in portrait in addition to the !=0 condition in my runnable. but first I'm not very proud of that way to do it, I'd rather be notified when the ImageView get it's final sizing. And I would prefer not passing the viewsize in my state bundle.
Is there a simpler way to achieve this ?
By the way I load the ImageView this way :
Picasso.with(iv.getContext())
.load(AppConstants.SERVER_URL + "/api/" + question.getImage().getUrl())
.config(Bitmap.Config.RGB_565)
.into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
iv.setImageBitmap(bitmap);
iv.setAdjustViewBounds(true);
}
#Override
public void onBitmapFailed(Drawable errorDrawable) {
}
#Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
}
});
I´ve got a SurfaceView that keeps to be square. i´ve notice thatn when android runtime is doing all the stuff for layout will measure the component again and again and you never can tell when is the last time and the number of executions does not seem to be related to the amount of components on the screen, it is not random but maybe has something to do with the layout constraints of all the stuff around.
here´s my class overriding the measure ion order to keep square:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int w = MeasureSpec.getSize(widthMeasureSpec);
int h = MeasureSpec.getSize(heightMeasureSpec);
int size = w;
if (w < h) {
setMeasuredDimension(widthMeasureSpec, widthMeasureSpec);
} else {
size = h;
setMeasuredDimension(heightMeasureSpec, heightMeasureSpec);
}
if (h > 0 && squareSurfaceViewListener != null) {
squareSurfaceViewListener.onChangeSize(size);
}
}
So I´d inherit the imageview, detect the change and reload the image.
Using picasso it´ll cache the stuff but, maybe, you could forget about that and call for a new load each time the component is measured or add some kind of observer in the middle.

VideoView doesn't scale content to match its parent

I am using the DraggablePanel library (https://github.com/pedrovgs/DraggablePanel) to facilitate a YouTube like video player. If you are not familiar with this feature it basically allows the user to shrink the currently playing video into a small thumbnail that is docked into the corner of the screen.
Unfortunately (and I am not so sure this is an issue with the above library) I have noticed that if I apply an X and Y scale on the parent view of a VideoView, the VideoView itself will not resize its content to match.
See below screenshots, where VideoView is at its natural scale and then with its parent view scaled down to about 0.6:0.6. You should notice that in the scaled screenshot the VideoView has cropped its content instead of resizing to fit.
So I tried to force a width and height on the VideoView as its parent's scale changed. There are a few examples on the internet about overriding the dimensions of a VideoView - but here is my simple version:
public class ScalableVideoView extends VideoView {
private int mVideoWidth;
private int mVideoHeight;
public ScalableVideoView(Context context) {
super(context);
}
public ScalableVideoView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ScalableVideoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mVideoWidth = 0;
mVideoHeight = 0;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mVideoWidth > 0 && mVideoHeight > 0) {
// If a custom dimension is specified, force it as the measured dimension
setMeasuredDimension(mVideoWidth, mVideoHeight);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
public void changeVideoSize(int width, int height) {
mVideoWidth = width;
mVideoHeight = height;
getHolder().setFixedSize(width, height);
requestLayout();
invalidate();
}
}
The fragment that contains the VideoView is responsible for calling changeVideoSize on it when it receives a notification from the DraggablePanel library about a change in scale. At which point I calculate a new pair of width and height based on the provided scale values. (scale is from 0f to 1f)
public void setVideoViewScale(float scaleX, float scaleY) {
if (mMaxVideoWidth == 0) {
mMaxVideoWidth = mVideoView.getWidth();
}
if (mMaxVideoHeight == 0) {
mMaxVideoHeight = mVideoView.getHeight();
}
if (mMaxVideoWidth > 0) {
mVideoView.changeVideoSize((int) (scaleX * mMaxVideoWidth),
(int) (scaleY * mMaxVideoHeight));
}
}
Unfortunately this causes some really interesting results. It seems that the Video portion of the VideoView is scaling appropriately - but the bounds of the VideoView seem to be scaling too fast (causing the video to both shrink and crop).
For further demonstration here are two videos:
https://github.com/npike/so_scalevideoview/blob/master/demo_videos/so_videoview_noscale.mp4
https://github.com/npike/so_scalevideoview/blob/master/demo_videos/so_videoview_scale.mp4
I have also uploaded this sample project to GitHub so that you can see the complete code:
https://github.com/npike/so_scalevideoview
I was having the same problem with my app, so I took your example that is much simpler, and tried to fix it.
This is the code that fixes the problem. Edit your changeVideoSize(int width, int height) method to:
public void changeVideoSize(int width, int height){
mVideoWidth = width;
mVideoHeight = height;
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(width, height);
lp.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE);
lp.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
setLayoutParams(lp);
requestLayout();
invalidate();
}
With the invalidation of the view you force the VideoView to redraw the whole View with the new layout parameters.
I believe VideoView does not support scaling. Within the sample app that comes with DraggablePanel, there is a VideoSampleActivity, which demonstrates a draggable video. In order to achieve an effect like scaling, the top_view_resize attribute is set to true within activity_video_sample.xml:
<com.github.pedrovgs.DraggableView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:draggable_view="http://schemas.android.com/apk/res-auto"
android:id="#+id/draggable_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
draggable_view:top_view_id="#+id/video_view"
draggable_view:bottom_view_id="#+id/iv_thumbnail"
draggable_view:top_view_x_scale_factor="#dimen/x_scale_factor"
draggable_view:top_view_y_scale_factor="#dimen/y_scale_factor"
draggable_view:top_view_height="#dimen/top_fragment_height"
draggable_view:top_view_margin_right="#dimen/top_fragment_margin"
draggable_view:top_view_margin_bottom="#dimen/top_fragment_margin"
draggable_view:enable_minimized_horizontal_alpha_effect="false"
draggable_view:top_view_resize="true"
android:background="#color/black">
Setting top_view_resize to true causes the TransformerFactory to return a ResizeTransformer instead of a ScaleTransformer. The ResizeTransformer uses setLayoutParams() to resize the associated View, where the ScaleTransformer applies a scale factor.
Rather than attempting to scale the VideoView, you should be able to set top_view_resize to true.
Note: if you use a DraggablePanel (which supports top and bottom fragments) instead of a DraggableView, you currently do not have access to the top_view_resize attribute of the DraggableView that's nested inside the DraggablePanel. I consider this to be a bug, and I'm hoping I can work with Pedro to expose a top_view_resize attribute on DraggablePanel that will pass its value through to the nested DraggableView. As a result of this bug, DraggablePanel always uses the default Transformer, which is the ScaleTransformer -- which does not work with a VideoView.

create a 16:9 view

I am writing a program that I would like to have a 16:9 screen all the time. I set up a basic linearlayout to host 2 object that I write. The first one overwrite the onMeasure method, so that it'll take a "square" space from the screen, and the second object take the rest. This looks good on a 16:9 device that I have. But when I tried it out on other device, it just looks bad. I tried to extend from the linearlayout that host my object, and overwrite the onMeasure method for the layout. The custom Linearlayout seems to do the 16:9 fine, but my first object (the square), is still getting the big square, not a smaller square confined to the 16:9 strip. Here are the relavent code
MainActivity:
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
layout = new MyLinear(this);
mField = new Field(this);
mField.setId(1);
control = new Controller(this);
control.setId(2);
layout.addView(mField);
layout.addView(control);
registerForContextMenu(control);
setContentView(layout);
mField.requestFocus();
}
the onMeasure code for the custom linearlayout looks like this
public class MyLinear extends LinearLayout{
private int height, width; // dimension of the screen
private Context m_context;
public MyLinear(Context context) {
super(context);
m_context=context;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int height_temp = View.MeasureSpec.getSize(heightMeasureSpec);
int width_temp = View.MeasureSpec.getSize(widthMeasureSpec);
double ratio = width_temp/(double)height_temp;
int final_height = (int) (width_temp/1.77);
height=final_height;
if (ratio<1.7) {
setMeasuredDimension(width_temp, (int) (width_temp/1.77));
} else {
setMeasuredDimension(width_temp, height_temp);
}
}
anyone has a better suggestion?
You edit, view.xml file. Add res/layout-xlarge/my_layout.xml folder. after add my_layout.xml file res/layout-xlarge/ folder... I'm sorry for bad english

VideoView content resize

I have a VideoView which is set to fill parent and works fine with full size videos ,I am finding it difficult to find a solution when video size is 4:3 or smaller it keeps to left of my view whereas same application in ios display's it in full screen.
Can we resize the video and show it with same size of that of a Video View?or can content of VideoView resized?
I tried
view.measure(View.MeasureSpec.EXACTLY, View.MeasureSpec.EXACTLY);
but no results
Make a custom video class like this:
public class CustomVideoView extends VideoView {
protected int _overrideWidth = 480;
protected int _overrideHeight = 360;
public CustomVideoView(Context context) {
super(context);
}
public CustomVideoView(Context context, AttributeSet set) {
super(context, set);
}
public void resizeVideo(int width, int height) {
_overrideHeight = height;
_overrideWidth = width;
// not sure whether it is useful or not but safe to do so
getHolder().setFixedSize(width, height);
//getHolder().setSizeFromLayout();
requestLayout();
invalidate(); // very important, so that onMeasure will be triggered
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
setMeasuredDimension(_overrideWidth, _overrideHeight);
}
}
In your class use the resizeVideo method with the screen width and height as parameters.
Take in account that all depends on the movie ratio and the screen ratio. If they are the same, than the video is displayed full screen, but when they are different, the video is adjusted on width/height.

Issue on zoom VideoView

I'm struggling with this video issue for a while. I thought you may have some ideas to help me.
So I'm having this VideoView in a frame layout and on top I have a ToggleButton to make zoom and came back from zoom.
<CustomVideoView
android:id="#+id/video_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:keepScreenOn="true" >
</CustomVideoView>
and I have a video 480x360 and I thought that when making zoom in portrait, I will resize it at the screen height and the calculated width, based on the video ratio.(in landscape otherwise).
I have extended VideoView to CustomVideoView using:
public class CustomVideoView extends VideoView {
protected int _overrideWidth = 480;
protected int _overrideHeight = 360;
public CustomVideoView(Context context) {
super(context);
}
public CustomVideoView(Context context, AttributeSet set) {
super(context, set);
}
public void resizeVideo(int width, int height) {
_overrideHeight = height;
_overrideWidth = width;
// not sure whether it is useful or not but safe to do so
getHolder().setFixedSize(width, height);
requestLayout();
invalidate(); // very important, so that onMeasure will be triggered
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
setMeasuredDimension(_overrideWidth, _overrideHeight);
}
}
on some devices the trick works fine, but on Google Nexus with 4.0.3 it stretches the video to the screen and on Galaxy S 2.3.3 it doesn't work at all.
It may be dependent on underlying native code, that is vendor (Samsung in your case) used for SurfaceView (and so on VideoView) realisation. Also MediaPlayer, which is part of VideoView too, can have device-specific realisation (also native), and it can affect all VideoView behavior.

Categories

Resources