drawPin method

  1. @override
void drawPin(
  1. Canvas canvas,
  2. Size size,
  3. String text,
  4. int pinLength,
  5. Cursor? cursor,
  6. TextDirection textDirection,
)
override

Implementation

@override
void drawPin(
  Canvas canvas,
  Size size,
  String text,
  int pinLength,
  Cursor? cursor,
  TextDirection textDirection,
) {
  /// Calculate the height of paint area for drawing the pin field.
  /// it should honor the error text (if any) drawn by
  /// the actual texfield behind.
  /// but, since we can access the drawn textfield behind from here,
  /// we use a simple logic to calculate it.
  double mainHeight;
  if (errorText != null && errorText!.isNotEmpty) {
    mainHeight = size.height - (errorTextStyle?.fontSize ?? 0 + 8.0);
  } else {
    mainHeight = size.height;
  }

  Paint borderPaint = Paint()
    ..strokeWidth = strokeWidth
    ..style = PaintingStyle.stroke
    ..isAntiAlias = true;

  /// Assign paint if [solidColor] is not null
  Paint? insidePaint;
  if (bgColorBuilder != null) {
    insidePaint = Paint()
      ..style = PaintingStyle.fill
      ..isAntiAlias = true;
  }

  double gapTotalLength = gapSpaces?.sumList() ?? (pinLength - 1) * gapSpace;

  /// Calculate the width of each digit include stroke.
  double singleWidth =
      (size.width - strokeWidth - gapTotalLength) / pinLength;

  double radius; // include strokeWidth
  List<double> actualGapSpaces;
  if (singleWidth / 2 < mainHeight / 2 - strokeWidth / 2) {
    radius = singleWidth / 2;
    actualGapSpaces =
        gapSpaces == null ? List.filled(pinLength - 1, gapSpace) : gapSpaces!;
  } else {
    radius = mainHeight / 2 - strokeWidth / 2;
    actualGapSpaces = List.filled(
        pinLength - 1,
        (size.width - strokeWidth - radius * 2 * pinLength) /
            (pinLength - 1));
  }

  double startX = strokeWidth / 2;
  double startY = mainHeight / 2;

  List<double> centerPoints = List.filled(pinLength, 0.0);

  /// Draw the each shape of pin.
  for (int i = 0; i < pinLength; i++) {
    if (errorText != null && errorText!.isNotEmpty) {
      /// only draw error-color as border-color or solid-color
      /// if errorText is not null
      borderPaint.color =
          errorTextStyle?.color ?? strokeColorBuilder.indexProperty(i);
    } else {
      borderPaint.color = strokeColorBuilder.indexProperty(i);
    }
    centerPoints[i] = startX + radius;
    canvas.drawCircle(
      Offset(centerPoints[i], startY),
      radius,
      borderPaint,
    );
    if (insidePaint != null) {
      canvas.drawCircle(
        Offset(startX + radius, startY),
        radius - strokeWidth / 2,
        insidePaint..color = bgColorBuilder!.indexProperty(i),
      );
    }
    startX += (radius * 2 + (i == pinLength - 1 ? 0 : actualGapSpaces[i]));
  }

  /// The char index of the [text]
  var index = 0;
  startY = 0.0;

  /// Determine whether display obscureText.
  bool obscureOn = obscureStyle?.isTextObscure == true;
  TextPainter textPainter;

  for (var rune in text.runes) {
    String code;
    if (obscureOn) {
      code = obscureStyle!.obscureText;
    } else {
      code = String.fromCharCode(rune);
    }
    textPainter = TextPainter(
      text: TextSpan(
        style: textStyle,
        text: code,
      ),
      textAlign: TextAlign.center,
      textDirection: textDirection,
    );

    /// Layout the text.
    textPainter.layout();

    /// No need to compute again
    if (startY == 0.0) {
      startY = mainHeight / 2 - textPainter.height / 2;
    }
    textPainter.paint(
        canvas,
        Offset(
          centerPoints[index] - textPainter.width / 2,
          startY,
        ));
    index++;
  }

  /// Setup the cursor.
  final int cursorIndex = index;
  Offset? cursorOffset;

  /// Fill the remaining space with hint text.
  if (hintText != null) {
    hintText!.substring(index).runes.forEach((rune) {
      String code = String.fromCharCode(rune);
      textPainter = TextPainter(
        text: TextSpan(
          style: hintTextStyle,
          text: code,
        ),
        textAlign: TextAlign.center,
        textDirection: textDirection,
      );

      /// Layout the text.
      textPainter.layout();

      /// Save the size of the first hint text to offset the cursor.
      if (index == cursorIndex) {
        cursorOffset = Offset(textPainter.size.width / 2, 0);
      }

      startY = mainHeight / 2 - textPainter.height / 2;
      textPainter.paint(canvas,
          Offset(centerPoints[index] - textPainter.width / 2, startY));
      index++;
    });
  }

  /// Draw the cursor if provided.
  if (cursor != null && cursor.enabled && cursorIndex < pinLength) {
    drawCursor(
      canvas,
      size,
      Rect.fromLTWH(
        radius * cursorIndex * 2 +
            actualGapSpaces.take(cursorIndex).sumList(),
        0,
        radius * 2,
        size.height,
      ),
      cursor,
      cursorOffset,
      textDirection,
    );
  }
}