从先前的布局方向在相同位置重画多个路径 [英] Redraw multiple Paths at same positions from previous layout orientation

查看:83
本文介绍了从先前的布局方向在相同位置重画多个路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

上部布局是一个简单的自定义DrawView,它具有用户绘制的Path s的ArrayList.设备旋转时,它将调出onDraw()并多次调用canvas.drawPath().但是,重新绘制Path具有与以前相同的坐标,但是位置和布局大小不同.这些屏幕快照展示了实际的行为:

The upper layout is a simple custom DrawView which has an ArrayList of Paths drew by the user. When the device rotates, it recalls onDraw() and calls several times canvas.drawPath(). However, the Paths are redrew with the same coordinates as before but on a different position and layout size. These screenshots demonstrate the actual behavior:

左:肖像-右:风景

但是当方向改变时,我想保持相同的坐标和位置,就像这样:

But I want to keep the same coordinates and positions when the orientation changed, like this:

左:与以上相同的肖像-右:具有人像"坐标的风景

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

Locking my activity with android:orientation="portrait" is not the expected solution. I use android:configChanges="orientation" and an OrientationListener to detect the rotation and prevent the total recreation of the Activity.

  • 我尝试在onLayout()中设置其他位置,但是显然,这不是正确的方法.
  • 我以前曾尝试过像这样转换多个Path:

  • I tried to set other different positions in onLayout() but obviously, this is not the right way.
  • I previously tried to transform the multiple Paths like this:

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);
}

  • 我还尝试如下旋转画布:

  • I also tried to rotate the canvas as follows:

    @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();
    }  
    

  • 无论如何,我尝试了许多操作,但在这种情况下似乎没有任何效果.是否有人能分享一个聪明绝妙的主意,从而使我朝正确的方向发展?
    预先感谢您的帮助.

    Anyway, I tried many manipulations but nothing seems to work in this specific case. Does someone have a bright and fabulous idea to share which can lead me in the right direction?
    Thanks in advance for the help.

    推荐答案

    更新:方法已简化,易于遵循.示例应用程序已更新.

    Update: Methodology has been simplified and made easier to follow. The sample app has been updated.

    我想我了解您正在尝试做的事情.您希望图形保持其与定义的StickyCaptureLayout的关系.我喜欢使用PathMatrix转换的方法.

    I think I understand what you are trying to do. You want the graphic to maintain its relationship with the StickyCaptureLayout that you have defined. I like the approach using Path and Matrix transformations.

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

    After determining the rotation that the device has undergone, create a Matrix to do the appropriate rotation and rotate about the center of the graphic.

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

    此处oldBounds是图形在定位之前的边界.我们将使用它来确定旋转图形上的边距.继续旋转

    Here oldBounds is the bounds of the graphic before location. We will use this to determine margins on the rotated graphic. Go ahead and do the rotation

    mPath.transform(mMatrix)
    

    图形已旋转,但位置不正确.它处于旧位置,但已旋转.创建翻译Matrix,将Path移动到适当的位置.实际计算取决于旋转.对于90度旋转,计算为

    The graphic has been rotated but its position is not correct. It is in the old position but rotated. Create a translation Matrix to move the Path to the appropriate location. The actual computation is dependent upon the rotation. For a 90 degree rotation the computation is

    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宽度.

    where transY is the Y-translation and transX is the X-translation. oldBounds is the pre-rotation bounds and newBounds is the post-rotation bounds. Important to note here is that getWidth() will give you the "old" View height and getHeight() will give you the old View width.

    这是一个示例程序,可以实现我上面描述的内容.接下来是几个图形,显示了使用此示例应用程序的90度旋转.

    Here is a sample program that accomplishes what I have described above. A couple of graphics follow showing a 90 degree rotation using this sample app.

    演示应用

    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;
            }
        }
    }
    

    肖像

    风景

    这篇关于从先前的布局方向在相同位置重画多个路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆