ZoomableTextureView icon indicating copy to clipboard operation
ZoomableTextureView copied to clipboard

How to prevent resize below original size?

Open tickerguy opened this issue 7 years ago • 5 comments

Setting "minScale='1'" does not do it. You can still resize below the original TextureView size, which looks very odd and also glitches badly if you have a light theme background.

I have figured out how to set the original view's parameters to maintain the aspect ratio (which for a SurfaceView appears to initialize properly automatically, but does not for a TextureView even with orientation set explicitly to vertical) but I cannot find the original scale value of the view in initView and, if someone tries to resize the view smaller than that cap the scale to the original level when the view was established.

It appears that "minScale" and "maxScale" are intended to prevent this but they don't -- the code looks right in onScale but isn't preventing the problem.

In addition it would be nice to have a double-tap reset scaling to the original value.

Example code demonstrating the problem -- play something in landscape and try to pinch it smaller. You can't. Then pinch zoom it LARGER, then back to smaller below the original "fills the screen" width. You should not be able to with the minScale set to 1 but you can in fact shrink the view below the screen width.

package net.cudasystems.android.videotest;

import android.net.Uri;
import android.os.Bundle;
import android.support.constraint.ConstraintLayout;
import android.support.v7.app.AppCompatActivity;
import android.util.DisplayMetrics;
import android.view.TextureView;

import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlayerFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;

import com.google.android.exoplayer2.util.Util;


public class MainActivity extends AppCompatActivity {

    private String mURL = "http://point-at-an-mp4 -file";

    TextureView mPlayerView;

    SimpleExoPlayer player = null;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mPlayerView = findViewById(R.id.video_view);
    }

    private void initializePlayer() {

        DefaultRenderersFactory renderersFactory =
                new DefaultRenderersFactory(this, DefaultRenderersFactory.EXTENSION_RENDERER_MODE_ON);


        player = ExoPlayerFactory.newSimpleInstance(
                renderersFactory,
                new DefaultTrackSelector(), new DefaultLoadControl());


        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);


        // Make sure the initial aspect ratio is 16:9 (otherwise a TextureView init's to the LARGER of
        // the two dimensions of the video irrespective of the orientation setting and screws the aspect ratio!)
        int width = metrics.widthPixels;
        int newHeight = (width * 9) / 16;
        mPlayerView.setLayoutParams(new ConstraintLayout.LayoutParams(width, newHeight));

        player.setVideoTextureView(mPlayerView);
        mPlayerView.invalidate();

        player.setPlayWhenReady(true);

        Uri uri = Uri.parse(mURL);
        MediaSource mediaSource = buildMediaSource(uri);
        player.prepare(mediaSource, true, true);
    }


    private MediaSource buildMediaSource(Uri uri) {

        return new ExtractorMediaSource.Factory(
                new DefaultHttpDataSourceFactory("exoplayer-codelab")).
                createMediaSource(uri);
    }


    @Override
    public void onStart() {
        super.onStart();
        if (Util.SDK_INT > 23) {
            if (player == null) {
                initializePlayer();
            }
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if ((Util.SDK_INT <= 23 || player == null)) {
            initializePlayer();
        }
    }
    @Override
    public void onPause() {
        super.onPause();
        if (Util.SDK_INT <= 23) {
            releasePlayer();
        }
    }
    @Override
    public void onStop() {
        super.onStop();
        if (Util.SDK_INT > 23) {
            releasePlayer();
        }
    }
    private void releasePlayer() {
        if (player != null) {
            player.release();
            player = null;
        }
    }

}

and the XML for this:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/root"
    android:focusable="true"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:keepScreenOn="true">

    <ua.polohalo.zoomabletextureview.ZoomableTextureView
        android:id="@+id/video_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="top"
        app:maxScale="4"
        app:minScale="1"/>

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Does This work?"
        android:textColor="@android:color/holo_red_dark"
        app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

tickerguy avatar May 28 '18 18:05 tickerguy

Ok, this is bizarre. With one source I cannot make it misbehave, with another I can..... looking into why now...

Found it -- if you rotate the device you're hosed. This appears to be related to use in a fragment (which is where one of my use cases is and why it didn't show up with some sources and instances of my attempts to use it but did with others); onRestoreInstanceState is not called on rotation in that case, and minScale winds up being zero. This obvious hack around this problem is to recognize the zero value and set it to "1.0f", but I'll see if I can come up with a better answer.

tickerguy avatar May 28 '18 19:05 tickerguy

Me too

animaonline avatar May 28 '18 20:05 animaonline

Biggest issue right now is figuring out why a "reset to default" (double-tap) isn't working correctly. I get the correct size but not the correct 0,0 x/y origin back -- and am not at all sure why.

tickerguy avatar May 28 '18 23:05 tickerguy

Pull request sent.

tickerguy avatar May 29 '18 01:05 tickerguy

@tickerguy : If Is it possible take a look at to my issue.

makazemi avatar Apr 20 '19 14:04 makazemi