O
O
Oleg2017-03-04 20:30:38
Android
Oleg, 2017-03-04 20:30:38

How to fix CustomViewGroup on Fragment?

Good day .. The situation is as follows: there is a component inherited from ViewGroup in which pinch-to-zoom is implemented, several more TextView and ImageView are placed inside. There are 3 Fragments in the application, each of which should have this component.. Example:

<?xml version="1.0" encoding="utf-8"?>
<name.launcher.view.ZoomableViewGroup
    android:layout_height="match_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    >
    <AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/ll2"
        >
    <ImageView
        android:src="@drawable/diff"
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"
        android:scaleType="centerCrop"
        android:layout_alignParentTop="true"
        android:layout_alignParentStart="true" />
    <TextView
        android:text="TextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tvPage" />
    <TextView
        android:text="TextView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/tvPage1" />
    <Button
        android:text="Button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_x="16dp"
        android:layout_y="193dp"
        android:id="@+id/btnUpdate" />
    </AbsoluteLayout>
</name.launcher.view.ZoomableViewGroup>

The first fragment is created correctly (the content is displayed, you can click on the buttons ) .., when paging, the others are displayed empty, only after several zoom-out operations do the contents of the component appear from one edge and then it can be moved along the fragment ..if you do not use this component, then the content all fragments are displayed normally .. Tell me what's the catch? Where should you look?
Component code:
public class ZoomableViewGroup extends ViewGroup {
    private enum Mode {
        NONE,
        DRAG,
        ZOOM
    }

    private ZoomableViewGroup.Mode mode = ZoomableViewGroup.Mode.NONE;
    private float scale = 1.0f;
    private float lastScaleFactor = 0f;
    private float mFocusY;

    private float mFocusX;
    private ScaleGestureDetector mScaleDetector;

    private static final float MIN_ZOOM = 1.0f;
    private static final float MAX_ZOOM = 3.5f;

    private float startX = 0f;
    private float startY = 0f;

    // How much to translate the canvas
    private float dx = 0f;
    private float dy = 0f;
    private float prevDx = 0f;
    private float prevDy = 0f;

    private Matrix mScaleMatrix = new Matrix();
    private Matrix mScaleMatrixInverse = new Matrix();

    private Matrix mTranslateMatrix = new Matrix();
    private Matrix mTranslateMatrixInverse = new Matrix();

    private float[] mInvalidateWorkingArray = new float[6];
    private float[] mDispatchTouchEventWorkingArray = new float[2];
    private float[] mOnTouchEventWorkingArray = new float[2];

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

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

    public ZoomableViewGroup(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        mScaleDetector = new ScaleGestureDetector(context, new ScaleListener());
        mTranslateMatrix.setTranslate(0, 0);
        mScaleMatrix.setScale(1, 1);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);
            Log.i("CUSTOM", "Width: " + child.getWidth());
            if (child.getVisibility() != GONE) {
                child.layout(l, t, l + child.getMeasuredWidth(), t + child.getMeasuredHeight());
            }
        }
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.save();
        //canvas.translate(startX, startY);
        //canvas.scale(scale, scale);
        super.dispatchDraw(canvas);
        postInvalidate();
        canvas.restore();
    }

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

        int childCount = getChildCount();
        for (int i = 0; i < childCount; i++) {
            View child = getChildAt(i);

            if (child.getVisibility() != GONE) {
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent motionEvent) {

        switch (motionEvent.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                Log.i("CUSTOM", "DOWN");
                if (scale > MIN_ZOOM) {
                    mode = Mode.DRAG;
                    startX = motionEvent.getX() - prevDx;
                    startY = motionEvent.getY() - prevDy;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (mode == Mode.DRAG) {
                    dx = motionEvent.getX() - startX;
                    dy = motionEvent.getY() - startY;
                }
                mTranslateMatrix.preTranslate(dx, dy);
                mTranslateMatrix.invert(mTranslateMatrixInverse);
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                mode = Mode.ZOOM;
                break;
            case MotionEvent.ACTION_POINTER_UP:
                mode = Mode.DRAG;
                break;
            case MotionEvent.ACTION_UP:
                Log.i("CUSTOM", "UP");
                mode = Mode.NONE;
                prevDx = dx;
                prevDy = dy;
                break;
        }
        mScaleDetector.onTouchEvent(motionEvent);

        if ((mode == Mode.DRAG && scale >= MIN_ZOOM) || mode == Mode.ZOOM) {
            getParent().requestDisallowInterceptTouchEvent(true);
            float maxDx = (child().getWidth() - (child().getWidth() / scale)) / 2 * scale;
            float maxDy = (child().getHeight() - (child().getHeight() / scale)) / 2 * scale;
            dx = Math.min(Math.max(dx, -maxDx), maxDx);
            dy = Math.min(Math.max(dy, -maxDy), maxDy);
            Log.i("CUSTOM", "Width: " + child().getWidth() + ", scale " + scale + ", dx " + dx
                    + ", max " + maxDx);
            applyScaleAndTranslation();
        }
        invalidate();

        return true;
    }

    private void applyScaleAndTranslation() {
        int childCount = getChildCount();
        child().setScaleX(scale);
        child().setScaleY(scale);
        child().setTranslationX(dx);
        child().setTranslationY(dy);
    }

    private View child() {
        return getChildAt(0);
    }

    private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
        @Override
        public boolean onScaleBegin(ScaleGestureDetector scaleDetector) {
            Log.i("CUSTOM", "onScaleBegin");
            return true;
        }

        @Override
        public boolean onScale(ScaleGestureDetector detector) {

            float scaleFactor = detector.getScaleFactor();
            Log.i("CUSTOM", "onScale" + scaleFactor);

            if (detector.isInProgress()) {
                mFocusX = detector.getFocusX();
                mFocusY = detector.getFocusY();
            }

            if (lastScaleFactor == 0 || (Math.signum(scaleFactor) == Math.signum(lastScaleFactor))) {
                scale *= scaleFactor;
                scale = Math.max(MIN_ZOOM, Math.min(scale, MAX_ZOOM));
                lastScaleFactor = scaleFactor;
            } else {
                lastScaleFactor = 0;
            }
            invalidate();
            requestLayout();
            return true;
        }
    }

}

Answer the question

In order to leave comments, you need to log in

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question