代码之家  ›  专栏  ›  技术社区  ›  Marcin Wróblewski

基于视图在父级中的位置呈现位图

  •  0
  • Marcin Wróblewski  · 技术社区  · 6 年前

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

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

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

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

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

    我的问题是:

    Image generated via drawing views state Image generated via views to image function

    第一个图像是通过保存父视图状态生成的。第二种方法是将视图的位置、旋转和比例转换到画布上。 如你所见,在画布上,没有缩放的贴纸被正确定位,但是缩放的贴纸被错误定位。

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

    1 回复  |  直到 6 年前
        1
  •  0
  •   Marcin Wróblewski    6 年前

    我自己解决了这个问题。 结果我的解几乎可以,但我没有考虑到我对矩阵的操作 是否更改了原始点的排列 ,所以我的

    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 方法是我问题的答案-它只返回点 之后 转换。