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.
Related
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.
I have made a custom view by extend the View class. Currently I have an int which defines the size of view. Then I override the onMeasure method and made the width and height equal to the int.
Like this:
private int DEFAULT_SIZE = 80;
public Paint mOuterCirclePaint = new Paint();
#Override
protected void onDraw(Canvas canvas) {
mOuterCirclePaint.setStyle(Style.STROKE);
mOuterCirclePaint.setStrokeWidth(5.0f);
mOuterCirclePaint.setDither(true);
mOuterCirclePaint.setAntiAlias(true);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(
DEFAULT_SIZE + 5
+ (int) mOuterCirclePaint.getStrokeWidth() / 2,
DEFAULT_SIZE + 5
+ (int) mOuterCirclePaint.getStrokeWidth() / 2);
}
public void setSize(int defaultSize) {
DEFAULT_SIZE = defaultSize;
invalidate();
}
But this means my view does not scale well on different devices of different resolutions. On a high resolution device, the view appears small, but on a low resolution device, the view is large.
I don't think creating a new view for each resolution is a good idea. I have tried scaling the view my multiplying the DEFAULT_SIZE by the density of the device (float scale = getResources().getDisplayMetrics().density;), but this doesn't have an affect on the low res device, but makes the view take up more than the whole screen (you can't see it) on the high res device
So what is the best way to make a custom view for different devices? Am I on the right lines or is there a another way of doing it?
You could use dimension resources and use
int defaultSize = (int)context.getResources().getDimension(R.dimen.default_size);
in constructor of custom view with this in res/values/dimes.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="default_size">80dp</dimen>
</resources>
Now the size will be scaled due to density of the screen of device.
Here is simple example of measured view:
public class MeasuredView extends View
{
private int m_defaultSize;
public MeasuredView(Context context)
{
super(context);
init(context);
}
public MeasuredView(Context context, AttributeSet attrs)
{
super(context, attrs);
init(context);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
setMeasuredDimension(m_defaultSize, m_defaultSize);
}
private void init(Context context)
{
m_defaultSize = (int)context.getResources().getDimension(R.dimen.default_value);
}
}
On xhdpi size is 160 px, on hdpi its 120 and on mdpi its 80.
You should know that setSize(int defaultSize) takes argument value as pixels so if you want to set it as dp you can write method
public void setDefaultSizeDp(int defaultSizeDp)
{
int defaultSizePx = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, defaultSizeDp, getResources().getDisplayMetrics());
m_defaultSize = defaultSizePx;
invalidate();
}
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
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).
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.