从先前布局方向重绘相同位置的多个路径

fll*_*llo 8 android draw android-layout android-canvas android-orientation

基于我之前的问题" 如何在camera2 Android api中创建一个BottomBar作为StickyBottomCaptureLayout? ",我创建了一个带有StickyBar(SB)的布局,它始终锁定在系统栏上方/附近.我设置了SB的默认位置和坐标以及其他布局onLayout()(正如我的答案).

上部布局是一个简单的自定义DrawView,其中有一个Path由用户绘制的ArrayList .当设备旋转时,它会onDraw()多次调用并调用canvas.drawPath().但是,Paths是redrew,其坐标与之前相同,但位置和布局大小不同.这些屏幕截图演示了实际行为:

肖像 景观

左:肖像 - 右:风景

但是我希望在方向改变时保持相同的坐标和位置,如下所示:

肖像 lanscape

left:与上面相同的肖像 - 右:具有"纵向"坐标的横向

锁定我的活动android:orientation="portrait"不是预期的解决方案.我使用android:configChanges="orientation"和一个OrientationListener来检测旋转并防止整个娱乐Activity.

  • 我试图设置其他不同的位置,onLayout()但显然,这不是正确的方法.
  • 我之前试图Path像这样转换多个s:

    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's 
            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);
    }
    
    Run Code Online (Sandbox Code Playgroud)
  • 我还尝试按如下方式旋转画布:

    @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();
    }  
    
    Run Code Online (Sandbox Code Playgroud)

无论如何,我尝试了许多操作,但似乎在这个特定情况下似乎没有任何作用.有人有一个明亮而神话般的想法可以分享哪些可以引导我朝着正确的方向前进?
在此先感谢您的帮助.

Che*_*amp 2

更新:方法已经简化并且更容易遵循。示例应用程序已更新。

我想我明白你想做什么。您希望图形保持其与StickyCaptureLayout您定义的关系。我喜欢这种方法的使用PathMatrix转换。

确定设备经历的旋转后,创建一个Matrix进行适当的旋转并绕图形中心旋转。

mMatrix.postRotate(rotationDegrees, oldBounds.centerX(), oldBounds.centerY());
Run Code Online (Sandbox Code Playgroud)

oldBounds是定位之前图形的边界。我们将使用它来确定旋转图形的边距。继续进行旋转

mPath.transform(mMatrix)
Run Code Online (Sandbox Code Playgroud)

图形已旋转,但其位置不正确。它处于旧位置但已旋转。创建翻译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
Run Code Online (Sandbox Code Playgroud)

其中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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

肖像

在此输入图像描述

景观

在此输入图像描述