paint method

  1. @override
void paint(
  1. Canvas canvas,
  2. Size size,
  3. double progress,
  4. Offset center,
  5. Color color, {
  6. double radiusMultiplier = 1.0,
  7. Offset positionOffset = Offset.zero,
})
override

Implementation

@override
void paint(
    Canvas canvas, Size size, double progress, Offset center, Color color,
    {double radiusMultiplier = 1.0, Offset positionOffset = Offset.zero}) {
  final adjustedCenter = center + positionOffset;

  // Parameters
  final double maxShredLength = size.width * 0.6 * radiusMultiplier;

  // Jumlah strip kertas yang tersobek
  final int stripCount = 16;

  // Opacity kontrol
  double opacity = 1.0;
  if (progress < 0.1) {
    opacity = progress / 0.1; // Fade in
  } else if (progress > 0.9) {
    opacity = (1.0 - progress) / 0.9; // Fade out
  }

  // Menggambar border outline widget (simulasi kertas)
  final double paperSize = size.width * 0.5 * radiusMultiplier;

  // Warna background (kertas) - lighten dari warna dasar
  final Color paperColor = Color.lerp(Colors.white, color, 0.1)!;

  // Rect untuk kertas (sedikit lebih kecil dari widget)
  final Rect paperRect = Rect.fromCenter(
      center: adjustedCenter, width: paperSize, height: paperSize);

  // Style untuk kertas
  final Paint paperPaint = Paint()
    ..color = paperColor.withOpacity(opacity * 0.9)
    ..style = PaintingStyle.fill;

  // Menggambar kertas dengan sedikit rotasi
  canvas.save();
  canvas.translate(adjustedCenter.dx, adjustedCenter.dy);
  canvas.rotate(math.pi / 16); // Slight tilt
  canvas.translate(-adjustedCenter.dx, -adjustedCenter.dy);

  canvas.drawRect(paperRect, paperPaint);

  // Menggambar outline
  canvas.drawRect(
      paperRect,
      Paint()
        ..color = color.withOpacity(opacity * 0.7)
        ..style = PaintingStyle.stroke
        ..strokeWidth = 1.0);

  // Random untuk konsistensi
  final math.Random random = math.Random(42);

  // Menggambar shredding effect
  for (int i = 0; i < stripCount; i++) {
    // Random seed untuk strip ini
    final int stripSeed = i * 100;
    final random = math.Random(stripSeed);

    // ... continuing PaperShredAnimator
    // Posisi strip di tepi kertas
    final double normalizedPos = i / (stripCount - 1);

    // Pilih tepi mana yang tersobek (top, right, bottom, left)
    int edgeSide;
    if (i < stripCount / 4) {
      edgeSide = 0; // Top
    } else if (i < stripCount / 2) {
      edgeSide = 1; // Right
    } else if (i < 3 * stripCount / 4) {
      edgeSide = 2; // Bottom
    } else {
      edgeSide = 3; // Left
    }

    // Offset dalam edge berdasarkan posisi
    final double edgeNormalizedPos = (normalizedPos * 4) % 1.0;

    // Start point pada tepi kertas
    Offset startPoint;
    double shredAngle; // Sudut sobekan

    switch (edgeSide) {
      case 0: // Top edge
        startPoint = Offset(
            paperRect.left + paperRect.width * edgeNormalizedPos,
            paperRect.top);
        shredAngle =
            math.pi / 2 + (random.nextDouble() * math.pi / 4 - math.pi / 8);
        break;
      case 1: // Right edge
        startPoint = Offset(paperRect.right,
            paperRect.top + paperRect.height * edgeNormalizedPos);
        shredAngle =
            math.pi + (random.nextDouble() * math.pi / 4 - math.pi / 8);
        break;
      case 2: // Bottom edge
        startPoint = Offset(
            paperRect.right - paperRect.width * edgeNormalizedPos,
            paperRect.bottom);
        shredAngle = 3 * math.pi / 2 +
            (random.nextDouble() * math.pi / 4 - math.pi / 8);
        break;
      case 3: // Left edge
        startPoint = Offset(paperRect.left,
            paperRect.bottom - paperRect.height * edgeNormalizedPos);
        shredAngle = 0 + (random.nextDouble() * math.pi / 4 - math.pi / 8);
        break;
      default:
        startPoint = Offset(paperRect.left, paperRect.top);
        shredAngle = 0;
    }

    // Menghitung panjang sobekan berdasarkan progress
    // Muncul dengan cepat lalu stabil
    double shredProgress = progress < 0.4
        ? progress / 0.4
        : // Cepat di awal
        1.0; // Stabil setelahnya

    // Panjang strip
    final double stripLength =
        maxShredLength * shredProgress * (0.5 + random.nextDouble() * 0.5);

    // End point setelah sobekan
    final Offset endPoint = Offset(
        startPoint.dx + math.cos(shredAngle) * stripLength,
        startPoint.dy + math.sin(shredAngle) * stripLength);

    // Lebar strip
    final double stripWidth = 2.0 + random.nextDouble() * 3.0;

    // Path untuk strip
    final Path stripPath = Path();

    // Bentuk irregular untuk strip
    // Jalur zig-zag untuk sobekan kertas yang tidak rata
    stripPath.moveTo(startPoint.dx, startPoint.dy);

    // Jumlah segment zigzag
    final int zigzagCount = (stripLength / 10).round().clamp(3, 8);

    // Garis pertama lurus dari tepi
    final double straightLength = stripLength * 0.1;
    Offset currentPoint = Offset(
        startPoint.dx + math.cos(shredAngle) * straightLength,
        startPoint.dy + math.sin(shredAngle) * straightLength);
    stripPath.lineTo(currentPoint.dx, currentPoint.dy);

    // Menggambar zigzag
    for (int z = 1; z <= zigzagCount; z++) {
      final double segmentT = z / zigzagCount;

      // Posisi pada garis lurus
      final double baseX =
          startPoint.dx + (endPoint.dx - startPoint.dx) * segmentT;
      final double baseY =
          startPoint.dy + (endPoint.dy - startPoint.dy) * segmentT;

      // Vector perpendicular untuk zigzag
      final double perpX = -math.sin(shredAngle);
      final double perpY = math.cos(shredAngle);

      // Zigzag offset - alternate directions
      final double zigzagWidth = stripWidth * (1.0 + random.nextDouble());
      final double offset = (z % 2 == 0 ? 1 : -1) * zigzagWidth;

      // Final point dengan zigzag offset
      final Offset zigzagPoint =
          Offset(baseX + perpX * offset, baseY + perpY * offset);

      stripPath.lineTo(zigzagPoint.dx, zigzagPoint.dy);
      currentPoint = zigzagPoint;
    }

    // Memastikan akhir path mencapai endpoint
    stripPath.lineTo(endPoint.dx, endPoint.dy);

    // Menghitung titik kontrol untuk shadow jagged edge
    final List<Offset> jaggies = [];
    for (int j = 0; j <= 6; j++) {
      final double jT = j / 6.0;

      // Posisi pada garis
      final double jX = startPoint.dx + (endPoint.dx - startPoint.dx) * jT;
      final double jY = startPoint.dy + (endPoint.dy - startPoint.dy) * jT;

      // Perpendicular vector
      final double jPerpX = -math.sin(shredAngle);
      final double jPerpY = math.cos(shredAngle);

      // Random offset perpendicular
      final double jOffset = (random.nextDouble() * 2 - 1) * stripWidth;

      jaggies.add(Offset(jX + jPerpX * jOffset, jY + jPerpY * jOffset));
    }

    // Menggambar tepi sobek dengan shadow
    final Path shadowPath = Path();
    shadowPath.moveTo(startPoint.dx, startPoint.dy);

    // Menambahkan semua titik-titik jagged
    for (int j = 0; j < jaggies.length; j++) {
      shadowPath.lineTo(jaggies[j].dx, jaggies[j].dy);
    }

    // Menggambar shadow
    canvas.drawPath(
        shadowPath,
        Paint()
          ..color = Colors.black.withOpacity(opacity * 0.2)
          ..style = PaintingStyle.stroke
          ..strokeWidth = 1.0
          ..maskFilter = MaskFilter.blur(BlurStyle.normal, 2.0));

    // Menggambar strip dengan warna kertas
    canvas.drawPath(
        stripPath,
        Paint()
          ..color = paperColor.withOpacity(opacity)
          ..style = PaintingStyle.stroke
          ..strokeWidth = stripWidth
          ..strokeCap = StrokeCap.round);

    // Edge highlight
    canvas.drawPath(
        stripPath,
        Paint()
          ..color = color.withOpacity(opacity * 0.3)
          ..style = PaintingStyle.stroke
          ..strokeWidth = 0.5);
  }

  canvas.restore();
}