miuixGlassPopupFrame function

MiuixGlassPopupFrame miuixGlassPopupFrame({
  1. required MiuixGlassPopupMotion motion,
  2. required Rect anchor,
  3. required Size end,
  4. required Rect bounds,
  5. required double progress,
  6. required double positionProgress,
  7. double cornerRadius = 24,
  8. double gap = 0,
  9. EdgeInsets padding = const EdgeInsets.symmetric(vertical: 8),
  10. TextDirection direction = TextDirection.ltr,
})

上游菜单几何的纯函数移植;bounds 为扣除安全区、键盘和 safeMargin 后的范围。

Implementation

MiuixGlassPopupFrame miuixGlassPopupFrame({
  required MiuixGlassPopupMotion motion,
  required Rect anchor,
  required Size end,
  required Rect bounds,
  required double progress,
  required double positionProgress,
  double cornerRadius = 24,
  double gap = 0,
  EdgeInsets padding = const EdgeInsets.symmetric(vertical: 8),
  TextDirection direction = TextDirection.ltr,
}) {
  double lerp(double a, double b, double p) => lerpDouble(a, b, p)!;
  final rtl = direction == TextDirection.rtl;
  final x = (rtl ? anchor.left : anchor.right - end.width).clamp(
    bounds.left,
    math.max(bounds.left, bounds.right - end.width),
  );
  final below = bounds.bottom - anchor.top, above = anchor.bottom - bounds.top;
  final alignTop = end.height <= below || below >= above;
  final y = ((alignTop ? anchor.top : anchor.bottom - end.height) + gap).clamp(
    bounds.top,
    math.max(bounds.top, bounds.bottom - end.height),
  );
  final settled = Rect.fromLTWH(
        x.toDouble(),
        y.toDouble(),
        end.width,
        end.height,
      ),
      t = progress.clamp(0.0, 1.0);
  if (motion == MiuixGlassPopupMotion.secondary) {
    final left = (rtl ? anchor.right - end.width : anchor.left).clamp(
      bounds.left,
      math.max(bounds.left, bounds.right - end.width),
    );
    final top = anchor.top.clamp(
      bounds.top,
      math.max(bounds.top, bounds.bottom - end.height),
    );
    final target = Rect.fromLTWH(
      left.toDouble(),
      top.toDouble(),
      end.width,
      end.height,
    );
    final start = Rect.fromLTRB(
      anchor.left,
      anchor.top - padding.top,
      anchor.right,
      anchor.bottom + padding.bottom,
    );
    return MiuixGlassPopupFrame(Rect.lerp(start, target, t)!, cornerRadius);
  }
  if (motion == MiuixGlassPopupMotion.dialog) {
    final scale = lerp(.86, 1, progress);
    return MiuixGlassPopupFrame(
      Rect.fromCenter(
        center: bounds.center,
        width: end.width * scale,
        height: end.height * scale,
      ),
      cornerRadius * scale,
    );
  }
  if (motion == MiuixGlassPopupMotion.transform) {
    final width = math.max(.01, lerp(anchor.width, end.width, progress)),
        height = math.max(.01, lerp(anchor.height, end.height, progress));
    final center = Offset.lerp(
      anchor.center,
      settled.center,
      positionProgress,
    )!;
    return MiuixGlassPopupFrame(
      Rect.fromCenter(center: center, width: width, height: height),
      math.max(0, lerp(anchor.shortestSide / 2, cornerRadius, progress)),
    );
  }
  final ratio = end.width > 0 ? end.height / end.width : 1.0;
  if (motion == MiuixGlassPopupMotion.dropdown) {
    final startWidth = end.width * .69, startHeight = startWidth * .2;
    final width = math.max(.01, lerp(startWidth, end.width, progress)),
        height = math.max(.01, width * lerp(.2, ratio, progress));
    final startCenter = Offset(
      rtl ? settled.left + startWidth / 2 : settled.right - startWidth / 2,
      alignTop
          ? settled.top + startHeight / 2
          : settled.bottom - startHeight / 2,
    );
    return MiuixGlassPopupFrame(
      Rect.fromCenter(
        center: Offset.lerp(startCenter, settled.center, positionProgress)!,
        width: width,
        height: height,
      ),
      math.max(0, lerp(4, cornerRadius, progress)),
    );
  }
  final width = end.width * lerp(.15, 1, t),
      height = math.min(end.height, width * lerp(.2, ratio, t));
  return MiuixGlassPopupFrame(
    Rect.fromLTWH(
      rtl ? settled.left : settled.right - width,
      alignTop ? settled.top : settled.bottom - height,
      width,
      height,
    ),
    lerp(4, cornerRadius, t),
  );
}