Pinch to zoom MyTextureView just to screen dimension(width, height)

285 views Asked by At

Recently I used an implementation for a pinch to zoom in my TextureView using a SurfaceView. The zoom works perfectly but the view does not grow to the dimensions of the screen. In my case the TextureView is always in the dimensions 1080, 612. I would like to modify this zoom so that the view is filling the screen as I do the pinch.

Here is the code for my class that receives TextureView:

public class ScaleManager extends BaseInputManager {

    private final TextureView mTargetView;
    private final ScaleGestureDetector mScaleDetector;
    private static final float MIN_SCALE = 1.0f;
    private static final float MAX_SCALE = 5.0f;
    private float mCurrentScale = MIN_SCALE;
    private Matrix mMatrix = new Matrix();
    private float[] mMatrixValues = new float[9];
    private float mPreviousX;
    private float mPreviousY;
    private boolean mIsDragInProgress = false;

    public ScaleManager(TextureView view) {
        mTargetView = view;
        mScaleDetector = new ScaleGestureDetector(view.getContext(), new ScaleListener());
        mScaleDetector.setQuickScaleEnabled(false);
    }


    @Override
    public boolean handle(KeyEvent event) {
        return false;
    }

    @Override
    public boolean handle(MotionEvent event) {
        final int index = event.getActionIndex();
        final int type = event.getToolType(index);
        if (type == MotionEvent.TOOL_TYPE_FINGER || type == MotionEvent.TOOL_TYPE_STYLUS) {
            mScaleDetector.onTouchEvent(event);

            mMatrix.getValues(mMatrixValues);
            boolean isScaling = (mMatrixValues[Matrix.MSCALE_X] != 1.0f && mMatrixValues[Matrix.MSCALE_Y] != 1.0f);
            if (isScaling || mScaleDetector.isInProgress()) {
                switch (event.getAction()) {
                    case MotionEvent.ACTION_POINTER_DOWN:
                    case MotionEvent.ACTION_DOWN:
                        if (event.getPointerCount() <= 2) {
                            mPreviousX = event.getX();
                            mPreviousY = event.getY();
                        }

                        if (event.getPointerCount() == 2) {
                            mIsDragInProgress = true;
                        }
                        break;
                    case MotionEvent.ACTION_MOVE:
                        if (event.getPointerCount() == 2) {
                            float x = mMatrixValues[Matrix.MTRANS_X];
                            float y = mMatrixValues[Matrix.MTRANS_Y];

                            float width = mTargetView.getWidth();
                            float height = mTargetView.getHeight();

                            float right = width * mCurrentScale - width;
                            float bottom = height * mCurrentScale - height;

                            float deltaX = event.getX() - mPreviousX;// x difference
                            float deltaY = event.getY() - mPreviousY;// y difference

                            float scaledWidth = Math.round(width * mCurrentScale);// width after applying current scale
                            float scaledHeight = Math.round(height * mCurrentScale);// height after applying current scale
                            //if scaledWidth is smaller than the views width
                            //in other words if the image width fits in the view
                            //limit left and right movement
                            if (scaledWidth < width) {
                                deltaX = 0;
                                if (y + deltaY > 0) {
                                    deltaY = -y;
                                } else if (y + deltaY < -bottom) {
                                    deltaY = -(y + bottom);
                                }

                                //if scaledHeight is smaller than the views height
                                //in other words if the image height fits in the view
                                //limit up and down movement
                            } else if (scaledHeight < height) {
                                deltaY = 0;
                                if (x + deltaX > 0) {
                                    deltaX = -x;
                                } else if (x + deltaX < -right) {
                                    deltaX = -(x + right);
                                }

                                //if the image doesn't fit in the width or height
                                //limit both up and down and left and right
                            } else {
                                if (x + deltaX > 0) {
                                    deltaX = -x;
                                } else if (x + deltaX < -right) {
                                    deltaX = -(x + right);
                                }

                                if (y + deltaY > 0) {
                                    deltaY = -y;
                                } else if (y + deltaY < -bottom) {
                                    deltaY = -(y + bottom);
                                }
                            }

                            //move the image with the matrix
                            mMatrix.postTranslate(deltaX, deltaY);


                            mTargetView.setTransform(mMatrix);
                            mTargetView.invalidate();

                            mPreviousX = event.getX();
                            mPreviousY = event.getY();
                        }
                        break;
                    case MotionEvent.ACTION_POINTER_UP:

                    case MotionEvent.ACTION_UP:
                        if (event.getPointerCount() == 1) {
                            mIsDragInProgress = false;
                        }
                        break;
                }
            }


            return mScaleDetector.isInProgress() || mIsDragInProgress;
        }

        return false;
    }


    private class ScaleListener implements ScaleGestureDetector.OnScaleGestureListener {

        @Override
        public boolean onScaleBegin(ScaleGestureDetector detector) {
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {
            float width = mTargetView.getWidth();
            float height = mTargetView.getHeight();
            float factor = detector.getScaleFactor();
            float scale = mCurrentScale * factor;
            if (scale > MAX_SCALE) {
                factor = MAX_SCALE / mCurrentScale;
                mCurrentScale = MAX_SCALE;
            } else if (scale < MIN_SCALE) {
                factor = MIN_SCALE / mCurrentScale;
                mCurrentScale = MIN_SCALE;
            } else {
                mCurrentScale = scale;
            }

            if (width * scale <= width || height * scale <= height) {
                mMatrix.postScale(factor, factor, width / 2, height / 2);
            } else {
                mMatrix.postScale(factor, factor, detector.getFocusX(), detector.getFocusY());
            }

            if (factor < 1) {
                float right = width * mCurrentScale - width;
                float bottom = height * mCurrentScale - height;

                mMatrix.getValues(mMatrixValues);
                float x = mMatrixValues[Matrix.MTRANS_X];
                float y = mMatrixValues[Matrix.MTRANS_Y];

                if (x < -right) {
                    mMatrix.postTranslate(-(x + right), 0);
                } else if (x > 0) {
                    mMatrix.postTranslate(-x, 0);
                }

                if (y < -bottom) {
                    mMatrix.postTranslate(0, -(y + bottom));
                } else if (y > 0) {
                    mMatrix.postTranslate(0, -y);
                }
            }



            return true;
        }

        @Override
        public void onScaleEnd(ScaleGestureDetector detector) {
        }
    }


}

When I start the view I use a class called AspectFrameLayout to determine the initial ratio of the view. And this AspectFrameLayout is called each time the view is being modified to maintain the aspect ratio. Follow the code:

<com.examples.views.AspectRatioFrameLayout
    android:id="@+id/player_video"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center"
    android:focusable="true"
    android:focusableInTouchMode="true" />




mSurfaceView = layoutInflater.inflate(R.layout.texture_view, 
player_video_frame, false)

This is the AspectFrameLayout class that I use to keep the aspect ratio:

public final class AspectRatioFrameLayout extends FrameLayout {


    private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f;

    private float mVideoAspectRatio;

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

    public AspectRatioFrameLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
    }


    public void setAspectRatio(float ratio) {
        if (this.mVideoAspectRatio != ratio) {
            this.mVideoAspectRatio = ratio;
            requestLayout();
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mVideoAspectRatio == 0) {
            // Aspect ratio not set.
            return;
        }

        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        float viewAspectRatio = (float) width / height;
        float aspectDeformation = mVideoAspectRatio / viewAspectRatio - 1;
        if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) {
            // We're within the allowed tolerance.
            return;
        }

        if (aspectDeformation > 0) {
            height = (int) (width / mVideoAspectRatio);
        } else {
            width = (int) (height * mVideoAspectRatio);
        }
        super.onMeasure(
                MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)
        );
    }

}
0

There are 0 answers