首页 > 解决方案 > 基于父视图中的位置渲染位图

问题描述

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

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

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

    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功能来自这里

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

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

我的问题是:

通过绘图视图状态生成的图像 通过视图到图像功能生成的图像

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

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

标签: androidscaleandroid-canvasandroid-viewandroid-bitmap

解决方案


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

rootView.getWidth() / 2,
rootView.getHeight() / 2

Matrix.postScale调用或后不再适用于视图的中心Matrix.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方法是我问题的答案 - 它只是在转换后返回点。


推荐阅读