VideoView no escala el contenido para que coincida con su origen
Estoy utilizando la biblioteca DraggablePanel ( https://github.com/pedrovgs/DraggablePanel ) para facilitar un reproductor de vídeo de YouTube. Si no está familiarizado con esta función, básicamente, permite al usuario encoger el vídeo que se está reproduciendo en una pequeña miniatura que está acoplada en la esquina de la pantalla.
Desafortunadamente (y no estoy tan seguro de que esto sea un problema con la biblioteca anterior) he notado que si aplico una escala X e Y en la vista principal de un VideoView, el propio VideoView no cambiará el tamaño de su contenido para que coincida.
Vea más abajo las capturas de pantalla, donde VideoView está en su escala natural y luego con su vista primaria reducida a aproximadamente 0.6: 0.6. Debe notar que en la captura de pantalla escalada el VideoView ha recortado su contenido en lugar de cambiar el tamaño para que se ajuste.
Así que traté de forzar una anchura y una altura en el VideoView como la escala de su padre cambiado. Hay algunos ejemplos en el Internet sobre el reemplazo de las dimensiones de un VideoView – pero aquí está mi versión simple:
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(); } }
El fragmento que contiene el VideoView es responsable de llamar a changeVideoSize en él cuando recibe una notificación de la biblioteca DraggablePanel acerca de un cambio de escala. En este punto, calculo un nuevo par de ancho y alto basado en los valores de escala proporcionados. (La escala es de 0f a 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)); } }
Desafortunadamente esto causa algunos resultados realmente interesantes. Parece que la parte Video del VideoView está escalando apropiadamente – pero los límites del VideoView parecen estar escalando demasiado rápido (haciendo que el video se contraiga y recorte).
Para más demostración aquí hay dos 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
También he subido este proyecto de ejemplo a GitHub para que puedas ver el código completo: https://github.com/npike/so_scalevideoview
Yo estaba teniendo el mismo problema con mi aplicación, así que tomé su ejemplo que es mucho más simple, y trató de arreglarlo.
Este es el código que corrige el problema. Edite su método changeVideoSize (int width, int height) para:
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(); }
Con la invalidación de la vista, se obliga a VideoView a volver a dibujar toda la vista con los nuevos parámetros de diseño.
Creo que VideoView no es compatible con escalado. Dentro de la aplicación de ejemplo que viene con DraggablePanel, hay una VideoSampleActivity, que muestra un video arrastrable. Para lograr un efecto como escalado, el atributo top_view_resize se establece en true dentro de 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">
Establecer top_view_resize a true hace que TransformerFactory devuelva un ResizeTransformer en lugar de un ScaleTransformer. El ResizeTransformer utiliza setLayoutParams () para cambiar el tamaño de la vista asociada, donde el ScaleTransformer aplica un factor de escala.
En lugar de intentar escalar el VideoView, debería ser capaz de establecer top_view_resize como true.
Nota: si utiliza DraggablePanel (que admite fragmentos superior e inferior) en lugar de DraggableView, actualmente no tiene acceso al atributo top_view_resize de DraggableView anidado dentro de DraggablePanel. Considero que esto es un error, y espero poder trabajar con Pedro para exponer un atributo top_view_resize en DraggablePanel que pasará su valor a través del DraggableView anidado. Como resultado de este error, DraggablePanel siempre utiliza el transformador por defecto, que es el ScaleTransformer – que no funciona con un VideoView.