Как я могу анимировать изменение размера VideoView?

У меня есть VideoView, который я хочу динамически изменять размер в моем приложении. Расширяя класс VideoView, я успешно получил и video, и videoView для правильного изменения размера. Тем не менее, я хотел бы иметь возможность переходить между двумя размерами более постепенно. Как я могу это сделать? Я пробовал масштабную анимацию, но хотя это меняет размер макета VideoView, само видео не масштабируется. Мысли?

Вот мой видео класс:

public class MyVideoView extends VideoView {

    private int mForceHeight,mForceWidth;
    private int mOrigWidth, mOrigHeight, mMinWidth, mMinHeight;


    public MyVideoView(Context context) {
        super(context);
    }

    /* Will cause inflator errors if not present */
    public MyVideoView(Context context, AttributeSet attrs){
        super(context, attrs);
    }

    public void setDimensions(int w, int h) {
        this.mForceHeight = h;
        this.mForceWidth = w;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        if (mForceHeight != 0)
            setMeasuredDimension(mForceWidth, mForceHeight);
        else
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }


    public void setOrigDimens(int width, int height) {
        mOrigWidth = width;
        mOrigHeight = height;

        mMinWidth = width/4;    // My own decision for the small size
        mMinHeight = height/4;
    }


    public void setSmallView() {
        setNewViewSize(mMinWidth, mMinHeight);
    }


    public void setNormalView() {
        setNewViewSize(mOrigWidth, mOrigHeight);
    }


    /* RESIZES THE VIEW */
    public void setNewViewSize(int width, int height) {
        mForceWidth = width;
        mForceHeight = height;
        setDimensions(width, height);
        getHolder().setFixedSize(width, height);
    }
}

Вот код масштабирования, который я пробовал:

Animation scaling = new ScaleAnimation(1.0f, 0.2f, 1.0f, 0.2f);
scaling.setDuration(2000);
startAnimation(scaling);

Любая помощь высоко ценится!

2 ответа

Решение

Лучший ответ - просто использовать TextureView вместо SurfaceView (VideoView наследуется от SurfaceView по умолчанию). Для этого используйте код следующим образом:

Определите ваш TextureView в activity_main.xml:

<TextureView
    android:id="@+id/videoTexture"
    android:layout_width="match_parent"
    android:layout_height="match_parent />

В вашем MainActivity.java, объявите следующие переменные:

private MediaPlayer mMediaPlayer;
private TextureView mVideoTextureView;
private float mDisplayWidth;
private float mDisplayHeight;

Тогда в вашем onCreate() метод, инициализируйте их следующим образом:

mVideoTextureView =(TextureView) rootview.findViewById(R.id.videoTexture);
mVideoTextureView.setSurfaceTextureListener(this);

mMediaPlayer = new MediaPlayer();
loadNewMovie();

Чтобы загрузить фильм в MediaPlayer, используйте следующий код:

private void loadNewMovie() {

    AssetFileDescriptor afd = this.getResources().openRawResourceFd(ID_OF_YOUR_MOVIE);

    try {

        // Set source

        mMediaPlayer.reset();
        mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
        mMediaPlayer.prepare();

        /*
        // Gets the Height/Width of the video but does NOT include space
        // taken up by black bars if the dimensions don't exactly fit the screen.

        MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
        metaRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
        String height = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
        String width = metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
        mVideoHeight = Float.parseFloat(height);
        mVideoWidth = Float.parseFloat(width);
        */

        // Gets the size of the display in pixels (used for scaling)

        Display display = getWindowManager().getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);

        mDisplayWidth = size.x;
        mDisplayHeight = size.y;

        // Play movie

        if (currState == State.PLAYING)
            mMediaPlayer.start();

        afd.close();
    } 
    catch (Exception e) {
        Log.e("ERROR", "loadNewMovie: " + e.getMessage(), e);
    }

    mMediaPlayer.seekTo(DEFAULT_VIDEO_INIT_POSITION);
}

Наконец, ваше видео можно мгновенно настроить, используя следующий код:

private void updateTextureViewSize(int viewWidth, int viewHeight) {

    RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(viewWidth,viewHeight);

    // ANY OTHER RULES...EXAMPLE:
    // params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

    mVideoTextureView.setLayoutParams(params);
}

Или вы можете анимировать изменения следующим образом:

private void animateTextureViewScaling(final float startScaleX, final float startScaleY, 
                                       final float endScaleX, final float endScaleY, 
                                       int duration) {

    // Note: Can't just use .scaleX and .scaleY directly because it will only scale 
    // the video, not it's holder

    mVideoTextureView.animate().setDuration(duration)
        .setUpdateListener(new AnimatorUpdateListener() {

            float value, scalingX, scalingY;
            float changeXScale = startScaleX - endScaleX;
            float changeYScale = startScaleY - endScaleY;

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                value = (Float) animation.getAnimatedValue();

                scalingX = (float) (startScaleX - changeXScale*value);
                scalingY = (float) (startScaleX - changeYScale*value);

                RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
                        (int) (mDisplayWidth*scalingX), (int) (mDisplayHeight*scalingY));

                // ANY OTHER RULES...EXAMPLE:
                // params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);

                mVideoTextureView.setLayoutParams(params);
            }

        }).start();
}

В приведенном выше коде я использую mDisplayWidth (установлен в loadNewVideo()) как оригинальный размер моего видео. Вы можете использовать все, что вы хотите.

Преимущества этого в том, что TextureView можно анимировать, трансформировать и масштабировать (SurfaceView не может).

Недостатки в том, что TextureView можно использовать только в окне с аппаратным ускорением и использовать гораздо больше памяти (около 30%), чем SurfaceView. Также может наблюдаться задержка от 1 до 3 кадров.

Одно решение, которое я нашел, состоит в том, чтобы использовать ValueAnimator, чтобы изменить соотношение размеров, которое должно быть, и затем использовать обработчик обновлений, чтобы заставить видео фактически изменить размер. Тем не менее, это очень нервный

ValueAnimator scaleDown = ValueAnimator.ofFloat(1, 0.25f);
    scaleDown.setDuration(1000);

    scaleDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        public void onAnimationUpdate(ValueAnimator animation) {
            Float value = (Float) animation.getAnimatedValue();
            setNewViewSize(mOrigWidth*value, mOrigHeight*value);
        }
    });

    scaleDown.start();
Другие вопросы по тегам