【问题标题】:Why does Flex's Matrix Transform Snap Child Back to Top Corner of Parent?为什么 Flex 的矩阵变换将子节点拉回父节点的顶角?
【发布时间】:2011-04-14 18:42:53
【问题描述】:

我在 Flex 中遇到矩阵变换问题。

我有一个 Flex Canvas,里面只有一个图像,就像这样。

<mx:Canvas>
 <mx:Image id="img" source="/some/Url" />
</mx:Canvas>

对于这张图片,我使用如下代码应用缩放/旋转变换:

private function _rotateAndZoomImage(zoom:Number, angle:Number):void{
 var radians:Number = angle * (Math.PI / 180.0);
 var offsetWidth:Number = ( img.contentWidth/2.0 );
 var offsetHeight:Number = (  img.contentHeight/2.0 );
 var matrix:Matrix = new Matrix();

 matrix.translate(-offsetWidth, -offsetHeight);
 matrix.rotate(radians);
 //Do the zoom
 matrix.scale (zoom/100, zoom/100);
 matrix.translate(+offsetWidth, +offsetHeight);
 img.transform.matrix = matrix;
}

这一切都有效。但。图像是可拖动的。用户可以将其移动到画布内作为其父级的任何位置。

一旦图像被移动并应用了变换图像被“捕捉”回到原来的 0,0(画布左上角)位置被转换并在之后被留在那里 - 不是用户期望的地方。

在一天中大部分时间都在搞砸这个问题之后,我仍然无法弄清楚它到底为什么会这样做。有人吗?

编辑:请注意,在上述代码中没有两次调用 .translate() 时也会发生同样的情况。因此,以下代码还会在图像移动后将图像捕捉回画布的 0,0:

private function _rotateAndZoomImage(zoom:Number, angle:Number):void{
 var radians:Number = angle * (Math.PI / 180.0);

 var matrix:Matrix = new Matrix();
 matrix.rotate(radians);
 matrix.scale (zoom/100, zoom/100);
 img.transform.matrix = matrix;
}

杰克

【问题讨论】:

    标签: apache-flex matrix transform


    【解决方案1】:

    这是我修复它的方法。我在我的 Image 类中覆盖了名为 super.move() 的“移动”函数,然后将变换矩阵重置为我最初设置的值(在本例中为 _affineTransform)。

        override public function move(x:Number, y:Number):void
        {
            super.move(x,y);
            this.transform.matrix = _affineTransform;
        }
    

    Hacky,但看看会做...如果有人有更清洁的解决方案,请告诉我!

    【讨论】:

    • 原谅我的无知,但这不会导致无限循环吗?如果您说应用转换调用 move 并且您是从 move 方法的覆盖范围内应用转换?
    • 好点,但它不会导致无限循环。同样,我不确定这是否是正确的解决方案,但它确实有效。我认为这整个问题是 Flex 4 中的一个错误。我在 Flex 3 中没有这种行为。
    【解决方案2】:

    如果您查看mx.core.UIComponentset x() 覆盖的源代码,您将看到以下行:

     _layoutFeatures.layoutX = value
    

    基本上,它会忽略默认显示列表x 值并将位置存储在其他位置。真正的x 可能会在处理完完整布局后设置(替换您的翻译值)。您可能应该始终使用xyscaleXscaleYrotation 和任何其他相关属性。 Adobe 似乎并不打算让 Flex 支持常规的显示对象变换矩阵。

    【讨论】:

    • 有趣。感谢您深入研究。我很高兴我现在没有进一步尝试直接解决它。相反,我使用了一种解决方法,我将在稍后的答案中写到。我想将您的答案标记为答案,就像它一样,但我认为我的解决方法是我的答案,因为它解决了问题。对不起。
    【解决方案3】:

    我认为您可能需要在翻译中添加 x,y 值:

    private function _rotateAndZoomImage(zoom:Number, angle:Number):void{
     var radians:Number = angle * (Math.PI / 180.0);
     var offsetWidth:Number = ( img.contentWidth/2.0 );
     var offsetHeight:Number = (  img.contentHeight/2.0 );
     var matrix:Matrix = new Matrix();
    
     matrix.translate(-offsetWidth, -offsetHeight);
     matrix.rotate(radians);
     //Do the zoom
     matrix.scale (zoom/100, zoom/100);
     matrix.translate(img.x + offsetWidth, img.y + offsetHeight);
     img.transform.matrix = matrix;
    }
    

    【讨论】:

    • 嗯。这只会在您放大时将图像从画布的一侧发送出去。
    • 更进一步 - 我注意到,如果我在 scale/rotate 调用之前和之后删除了 .translate() 调用,它仍然会恢复到 0,0,所以我不确定翻译是否责备。
    • 我也遇到了同样的问题。你用的是 flex 4 对吧?我认为问题在于 UIComponent.move(x,y) 在您进行转换后被调用,并且重置 x,y 坐标以及转换矩阵的 tx 和 ty 变量。不确定修复是什么。
    • @hisham - 很高兴知道我并不孤单。我已经通过在第二个“内部”画布中添加图像来“修复”这个问题。图像不再被拖动,但内部画布会。对图像的任何转换现在都相对于内部画布的 0,0,这是我们移动的,所以总是在正确的位置。不过,我仍然对更清洁的方法感兴趣......
    • @jake,有趣的是我可以试试。我找到了另一个解决方案,请参阅我的答案。
    【解决方案4】:

    尝试设置。

    matrix.tx
    matrix.ty
    

    【讨论】:

    • 不就是和调用.translate()方法一样吗?
    • 你建议我将值设置为什么?
    • 你想要图片的位置
    【解决方案5】:

    解决方案/解决方法非常简单。而不是这个:

    <mx:Canvas>
     <mx:Image id="img" source="/some/Url" mouseDown="img.startDrag()" />
    </mx:Canvas>
    

    我现在有了这个:

    <mx:Canvas>
     <mx:Canvas id="inner" mouseDown="inner.startDrag()" clipContent="false">
      <mx:Image id="img" source="/some/Url" />
     </mx:Canvas>
    </mx:Canvas>
    

    可拖动的图像不再直接存在于主画布内。相反,它存在于一个子 Canvas 中。图像本身不再可拖动。被拖拽的是内部的 Canvas。

    现在,当对图像应用变换时,它会保持原样,因为它的父级的 0,0 坐标现在是它们应该在的位置,因为它是您将画布拖到的位置。

    希望这对某人有所帮助,并为他们节省我在这方面浪费的时间。 杰克

    【讨论】:

      猜你喜欢
      • 2020-07-27
      • 1970-01-01
      • 1970-01-01
      • 2013-01-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-18
      • 2015-11-07
      相关资源
      最近更新 更多