flutter 将坐标空间转换为“对齐”的更好方法

vlf7wbxs  于 2023-01-14  发布在  Flutter
关注(0)|答案(1)|浏览(118)

我正在尝试转换基于像素的x和y值的一个孩子在一个父,如Flutter的对齐x & y。
此代码改编自Flutter自己的Alignment.inscribe函数并受到其启发:
( typescript )

function convertPositionToAlignment(
  parentWidth: number,
  parentHeight: number,
  childX: number,
  childY: number,
  childWidth: number,
  childHeight: number
): AlignmentModel {
  const halfWidthDelta = (parentWidth - childWidth) / 2;
  const halfHeightDelta = (parentHeight - childHeight) / 2;

  let x;
  if (halfWidthDelta != 0) {
    x = (childX - halfWidthDelta) / halfWidthDelta;
  } else {
    x = 0;
  }
  let y;
  if (halfHeightDelta != 0) {
    y = (childY - halfHeightDelta) / halfHeightDelta;
  } else {
    y = 0;
  }

  return new AlignmentModel(new AlignmentData(x, y));
}

相反,Flutter的Alignment.inscribe函数如下:
( dart )

/// Returns a rect of the given size, aligned within given rect as specified
  /// by this alignment.
  ///
  /// For example, a 100×100 size inscribed on a 200×200 rect using
  /// [Alignment.topLeft] would be the 100×100 rect at the top left of
  /// the 200×200 rect.
  Rect inscribe(Size size, Rect rect) {
    final double halfWidthDelta = (rect.width - size.width) / 2.0;
    final double halfHeightDelta = (rect.height - size.height) / 2.0;
    return Rect.fromLTWH(
      rect.left + halfWidthDelta + x * halfWidthDelta,
      rect.top + halfHeightDelta + y * halfHeightDelta,
      size.width,
      size.height,
    );
  }

代码很简单,但是有一个问题,那就是如果子节点的大小等于父节点的大小,那么这将产生零值(如果没有if语句,它将产生infinite/NaN)。
我想知道,如果大小恰好相同,是否有任何方法可以计算对齐。这不是坐标空间的问题,而是对齐的问题。
我们希望消除这种边缘情况的原因是这样的情况:

对比:

这种图像大小与容器的盒子大小相同的边缘情况将导致y对齐为零,而在坐标空间中这是很容易做到的。

xmq68pz9

xmq68pz91#

相反,我们可以考虑子节点的中心在一个内部矩形空间中的偏移量,其中0,0是子节点的左上角与父节点的左上角接触的地方,而子节点的右下角与父节点的右下角接触的地方,这样我们就可以避免这种尴尬的划分。
在这种情况下我们的观点

childCenterX = childX + childWidth / 2;
childCenterY = childY + childHeight / 2;

在一个矩形内

minOffsetX = childWidth / 2;
minOffsetY = childHeight / 2;
maxOffsetX = parentWidth - minOffsetX;
maxOffsetY = parentHeight - minOffsetY;

偏移量为

offset = childCenter - minOffset;

并在-1..1之间归一化

innerWidth = maxOffsetX - minOffsetX;
innerHeight = maxOffsetY - minOffsetY;
offsetNormal = offset / innerSize * 2 - 1; // innerSize ≠ 0

编辑:如果父级和子级在一个或多个轴上的大小完全相同,内部大小仍然可以为零,因此一个快速而粗略的解决方案是:

double x, y;
if (innerWidth == 0) {
  x = child.x / child.width * 2 - 1;
} else {
  x = offsetX / innerWidth * 2 - 1;
}
if (innerHeight == 0) {
  y = child.y / child.height * 2 - 1;
} else {
  y = offsetY / innerHeight * 2 - 1;
}

Edit 2:一个更紧凑的 typescript 版本:

const deltaWidth = (parentWidth - childWidth) / 2;
const deltaX = deltaWidth === 0 ? childWidth : deltaWidth;
const x = (childX - deltaX) / deltaX;
    
const deltaHeight = (parentHeight - childHeight) / 2;
const deltaY = deltaHeight === 0 ? childHeight : deltaHeight;
const y = (childY - deltaY) / deltaY;

相关问题