根据父级中的视图位置渲染位图

Rendering Bitmap based on Views position in parent

我正在尝试制作一个简单的图像编辑器。一开始我认为将视图状态简单地保存为位图是个好主意,但事实证明,屏幕分辨率范围很广,这会导致巨大的质量(和内存使用)波动。

现在我正在尝试制作一个模块,以呈现转换为所需分辨率的视图状态。

在下面的代码中,我试图在 canvas 中重新创建视图的当前状态:

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.id.test_1_1);
    bitmap = Bitmap.createScaledBitmap(bitmap, parentView.getMeasuredWidth(), parentView.getMeasuredHeight(), true);

    Canvas canvas = new Canvas(bitmap);
    Paint paint = new Paint();
    for (View rootView : addedViews) {
        ImageView imageView = rootView.findViewById(R.id.sticker);

        float[] viewPosition = new float[2];
        transformToAncestor(viewPosition, parentView, imageView);

        Bitmap originalBitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
        Matrix adjustMatrix = new Matrix();
        adjustMatrix.postTranslate(viewPosition[0], viewPosition[1]);
        adjustMatrix.postScale(
                rootView.getScaleX(),
                rootView.getScaleY(),
                rootView.getWidth() / 2,
                rootView.getHeight() / 2);
        adjustMatrix.postRotate(rootView.getRotation(),
                rootView.getWidth() / 2,
                rootView.getHeight() / 2);

        canvas.drawBitmap(originalBitmap, adjustMatrix, paint);
    }

transformToAncestor 函数来自 here

public static void transformToAncestor(float[] point, final View ancestor, final View descendant) {
    final float scrollX = descendant.getScrollX();
    final float scrollY = descendant.getScrollY();
    final float left = descendant.getLeft();
    final float top = descendant.getTop();
    final float px = descendant.getPivotX();
    final float py = descendant.getPivotY();
    final float tx = descendant.getTranslationX();
    final float ty = descendant.getTranslationY();
    final float sx = descendant.getScaleX();
    final float sy = descendant.getScaleY();

    point[0] = left + px + (point[0] - px) * sx + tx - scrollX;
    point[1] = top + py + (point[1] - py) * sy + ty - scrollY;

    ViewParent parent = descendant.getParent();
    if (descendant != ancestor && parent != ancestor && parent instanceof View) {
        transformToAncestor(point, ancestor, (View) parent);
    }
}

(作者写了一个说明,他的功能不支持旋转,但我的例子中旋转不多,所以我现在认为这不重要)。

我的问题是:

第一张图片是通过保存父视图状态生成的。第二个是通过将视图位置、旋转和缩放转换到 canvas 上生成的。 如您所见,在canvas上,不是缩放的贴纸位置正确,而是缩放的位置不正确。

如何正确定位这些缩放视图?

我已经设法自己解决了这个问题。 事实证明我的解决方案几乎可以,但我没有考虑到我对矩阵的操作 确实改变了原始点的排列 ,所以我的

rootView.getWidth() / 2,
rootView.getHeight() / 2
在调用 Matrix.postScaleMatrix.postRotation 后,

不再适用于视图的中心。

我想:

  • 应用缩放,轴在左上角,
  • 应用旋转,轴位于视图中心。

鉴于假设,这里是工作代码:

    // setup variables for sizing and transformation
    float position[] = new float[2];
    transformToAncestor(position, rootView, imageView);
    float desiredRotation = imageView.getRotation();
    float sizeDeltaX = imageView.getMeasuredWidth() / (float) imageBitmap.getWidth();
    float sizeDeltaY = imageView.getMeasuredHeight() / (float) imageBitmap.getHeight();
    float desiredScaleX = imageView.getScaleX() * sizeDeltaX * scaleX;
    float desiredScaleY = imageView.getScaleY() * sizeDeltaY * scaleY;
    float imageViewWidth = imageView.getMeasuredWidth() * imageView.getScaleX();
    float imageViewHeight = imageView.getMeasuredHeight() * imageView.getScaleY();

    float rootViewWidth = rootView.getMeasuredWidth();
    float rootViewHeight = rootView.getMeasuredHeight();
    float percentXPos = position[0] / rootViewWidth;
    float percentYPos = position[1] / rootViewHeight;
    float percentXCenterPos = (position[0] + imageViewWidth/2)
            / rootViewWidth;
    float percentYCenterPos = (position[1] + imageViewHeight/2)
            / rootViewHeight;

    float desiredPositionX = background.getWidth() * percentXPos;
    float desiredPositionY = background.getHeight() * percentYPos;
    float desiredCenterX = background.getWidth() * percentXCenterPos;
    float desiredCenterY = background.getHeight() * percentYCenterPos;

    // apply above variables to matrix
    Matrix matrix = new Matrix();
    float[] points = new float[2];
    matrix.postTranslate(
            desiredPositionX,
            desiredPositionY);

    matrix.mapPoints(points);
    matrix.postScale(
            desiredScaleX,
            desiredScaleY,
            points[0],
            points[1]);

    matrix.postRotate(
            desiredRotation,
            desiredCenterX,
            desiredCenterY);

    // apply matrix to bitmap, then draw it on canvas
    canvas.drawBitmap(imageBitmap, matrix, paint);

如您所见,mapPoints 方法是我问题的答案 - 它只是 returns 指向 after 转型.