Redraw multiple paths at the same positions from the previous layout orientation

Based on my previous question about How to create a BottomBar as a StickyBottomCaptureLayout in camera2 Android api? ", I created a layout with StickyBar(SB) which is always locked above / next to the system panel. I set the default positions and the coordinates of SB and another layout to onLayout()(just like my answer ).

The top layout is a simple custom DrawViewone that has an ArrayList object Pathdrawn by the user. When the device rotates, it calls onDraw()and calls several times canvas.drawPath(). However, they are Pathrepeated with the same coordinates as before, but in a different position and layout. These screenshots demonstrate the actual behavior:

portrait landscape

left: portrait - right: landscape

But I want to keep the same coordinates and positions when the orientation has changed, for example:

portrait lanscape

left: the same portrait as above, right: landscape with "portrait" coordinates

Blocking my activity using is android:orientation="portrait"not an expected solution. I use android:configChanges="orientation"it OrientationListenerto detect rotation and prevent full recreation Activity.

  • onLayout(), , , .
  • Path :

    for (Path path : mPathList) {
        Matrix matrix = new Matrix();
        RectF bounds = new RectF();
        path.computeBounds(bounds, true);
    
        // center points to rotate
        final float px = bounds.centerX();
        final float py = bounds.centerY();
        // distance points to move 
        final float dx; // ?
        final float dy; // ?
        /** I tried many calculations without success, it 
            not worth to paste these dumb calculations here... **/
    
        matrix.postRotate(rotation, px, py); // rotation is 90°, -90° or 0
        matrix.postTranslate(dx, dy); // ?
        path.transform(matrix);
    }
    
  • :

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.save();
        canvas.rotate(rotation); // rotation is 90°, -90° or 0
    
        canvas.drawColor(mDrawHelper.getBackgroundViewColor());
        for (int i=0; i < mPathList.size(); i++) {
           canvas.drawPath(mPathList.get(i), mPaintList.get(i));
        }
        if (mPath != null && mPaint != null)
           canvas.drawPath(mPath, mPaint);
    
        canvas.restore();
    }  
    

, , . - , ?
.

+6
3

: . .

, , . , StickyCaptureLayout, . Path Matrix.

, , Matrix, .

mMatrix.postRotate(rotationDegrees, oldBounds.centerX(), oldBounds.centerY());

oldBounds - . .

mPath.transform(mMatrix)

, . , . Matrix, Path . . 90

transY = -newBounds.bottom; // move bottom of graphic to top of View
transY += getHeight(); // move to bottom of rotated view
transY -= (getHeight() - oldBounds.right); // finally move up by old right margin
transX = -newBounds.left; // Pull graphic to left of container
transX += getWidth() - oldBounds.bottom; // and pull right for margin

transY - Y-, transX - X-. oldBounds - , newBounds - . , getWidth() "" View getHeight() View.

, , . 90 .

-

package com.example.rotatetranslatedemo;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Bundle;
import android.view.Display;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;

public class MainActivity extends Activity {

    private DrawingView dv;
    private Paint mPaint;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        dv = new DrawingView(this);
        setContentView(dv);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.GREEN);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(12);
    }

    public class DrawingView extends View {

        private Bitmap mBitmap;
        private Path mPath;
        private Paint mBitmapPaint;
        Context context;
        private Paint paint;
        Matrix mMatrix = new Matrix();
        RectF oldBounds = new RectF();
        RectF newBounds = new RectF();

        public DrawingView(Context c) {
            super(c);
            context = c;
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(Color.BLUE);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.MITER);
            paint.setStrokeWidth(4f);
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);

            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
                    .getDefaultDisplay();
            int rotationDegrees = 0;
            float transX = 0;
            float transY = 0;

            super.onDraw(canvas);

            canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint);

            // Determine the rotation of the screen.
            switch (display.getRotation()) {
                case Surface.ROTATION_0:
                    break;

                case Surface.ROTATION_90:
                    rotationDegrees = 270;
                    break;

                case Surface.ROTATION_180:
                    rotationDegrees = 180;
                    break;

                case Surface.ROTATION_270:
                    rotationDegrees = 90;
                    break;

                default:
                    rotationDegrees = 0;
                    break;
            }

            if (mPath == null) { // Just define what we are drawing/moving
                mPath = setupGraphic();
            }

            // Reposition the graphic taking into account the current rotation.
            if (rotationDegrees != 0) {
                mMatrix.reset();
                // Rotate the graphic by its center and in place.
                mPath.computeBounds(oldBounds, true);
                mMatrix.postRotate(rotationDegrees, oldBounds.centerX(), oldBounds.centerY());
                mPath.transform(mMatrix);
                // Get the bounds of the rotated graphic
                mPath.computeBounds(newBounds, true);
                mMatrix.reset();
                if (rotationDegrees == 90) {
                    transY = -newBounds.bottom; // move bottom of graphic to top of View
                    transY += getHeight(); // move to bottom of rotated view
                    transY -= (getHeight() - oldBounds.right); // finally move up by old right margin
                    transX = -newBounds.left; // Pull graphic to left of container
                    transX += getWidth() - oldBounds.bottom; // and pull right for margin
                } else if (rotationDegrees == 270) {
                    transY = -newBounds.top; // pull top of graphic to the top of View
                    transY += getHeight() - oldBounds.right; // move down for old right margin
                    transX = getWidth() - newBounds.right; // Pull to right side of View
                    transX -= getHeight() - oldBounds.right; // Reestablish right margin
                }
                mMatrix.postTranslate(transX, transY);
                mPath.transform(mMatrix);
            }
            canvas.drawPath(mPath, mPaint);
        }

        // Define the graphix that we will draw and move.
        private Path setupGraphic() {
            int startX;
            int startY;
            final int border = 20;
            Path path;

            if (getHeight() > getWidth()) {
                startX = getWidth() - border - 1;
                startY = getHeight() - border - 1;
            } else {
                startX = getHeight() - border - 1;
                startY = getWidth() - border - 1;
            }
            startX = startX - 200;

            Pt[] myLines = {
                    new Pt(startX, startY),
                    new Pt(startX, startY - 500),

                    new Pt(startX, startY),
                    new Pt(startX - 100, startY),

                    new Pt(startX, startY - 500),
                    new Pt(startX - 50, startY - 400),

                    new Pt(startX, startY - 500),
                    new Pt(startX + 50, startY - 400),

                    new Pt(startX + 200, startY),
                    new Pt(startX + 200, startY - 500)
            };

            // Create the final Path
            path = new Path();
            for (int i = 0; i < myLines.length; i = i + 2) {
                path.moveTo(myLines[i].x, myLines[i].y);
                path.lineTo(myLines[i + 1].x, myLines[i + 1].y);
            }

            return path;
        }

        private static final String TAG = "DrawingView";

    }

    // Class to hold ordered pair
    private class Pt {
        float x, y;

        Pt(float _x, float _y) {
            x = _x;
            y = _y;
        }
    }
}

enter image description here

enter image description here

+3

№2 . , , .

, rotation int 90, -90 0, :

canvas.rotate(rotation); // rotation is 90°, -90° or 0

:

if (rotation == 90) {
    canvas.translate(canvas.getWidth(), 0);
    canvas.rotate(90);
} else if (rotation == -90) {
    canvas.translate(0, canvas.getHeight());
    canvas.rotate(-90);
}

. .

+1

, , . , , , , , , .

public class RotatedLayout extends FrameLayout {

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

    ...

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int rotation = 0;
        boolean swapDimensions = false;
        int translationX = 0;
        int translationY = 0;

        final Display display = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        switch (display.getRotation()) {
            case Surface.ROTATION_0:
                rotation = 0;
                break;
            case Surface.ROTATION_90:
                rotation = -90;
                swapDimensions = true;
                break;
            case Surface.ROTATION_180:
                rotation = 180;
                break;
            case Surface.ROTATION_270:
                rotation = 90;
                swapDimensions = true;
                break;
        }

        if (swapDimensions) {
            final int width = MeasureSpec.getSize(widthMeasureSpec);
            final int height = MeasureSpec.getSize(heightMeasureSpec);
            translationX = (width - height) / 2;
            translationY = (height - width) / 2;
            final int tmpMeasureSpec = heightMeasureSpec;
            heightMeasureSpec = widthMeasureSpec;
            widthMeasureSpec = tmpMeasureSpec;
        }
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        setTranslationX(translationX);
        setTranslationY(translationY);
        setRotation(rotation);
    }
}

. , . , , , . ( ) MeasureSpecs , , . - , , .

:

enter image description here

:

enter image description here

onConfigurationChanged

, - , . , onConfigurationChanged. Activity . :

  • ( AndroidManifest ) - .
  • -

enter image description here

, , , , , - artificial, .

, - no onConfigurationChanged, onMeasure, onLayout, onDraw .. ( ), RotatedLayout , . , .

, Dianne Hackborn.

. , , , , .

To solve this problem , you will need to use the SensorManager and register an OrientationEventListener to determine when to update your view instead of relying on the method onConfigurationChanged.

0
source

Source: https://habr.com/ru/post/1015977/


All Articles