Hasen
Hasen

Reputation: 12334

Flutter button with custom shape - (triangle)

I've created a circular button which in this case is RawMaterialButton and I'm trying to use CustomPaint to create a triangle shape in the centre of it, but it's saying ShapesPainter is not defined for the class ClearButton'. I tried other buttons but couldn't get any of them to acceptShapesPainter`.

RawMaterialButton(
          child: CustomPaint(
            painter: ShapesPainter(),
            child: Container(
              height: 40,
            ),
          ),
          onPressed: onPressed,
          constraints: BoxConstraints.tightFor(
            width: 90.0,
            height: 90.0,
          ),
          shape: RoundedRectangleBorder(),
          fillColor: Colors.transparent,
        )

Which button type should be used with ShapesPainter or how can I otherwise create a circular button with a triangle or another shape in the centre?

This is the button I was trying to create which as you can see is basically a circular button with a triangle.

enter image description here

Upvotes: 20

Views: 41781

Answers (5)

Muhammadjon Latifov
Muhammadjon Latifov

Reputation: 1

This star is created with ClipPath

import 'dart:math';
import 'package:flutter/material.dart';

class MyClipPath extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ClipPath(
        clipper: MyClipper(MediaQuery.of(context).size),
        child: Container(
          color: Colors.green,
        ),
      ),
    );
  }
}

class MyClipper extends CustomClipper<Path> {
  MyClipper(this.containerSize);
  Size containerSize;
  @override
  Path getClip(Size size) {
    var path = Path();

    double x = containerSize.width / 2;
    double y = 0;
    double radian = 0;
    double step = min(containerSize.width, containerSize.height / cos(0.1 * pi)) / pow(2 * sin(.3 * pi), 2);
    path.moveTo(x, y);
    for (var i = 0; i < 10; i++) {
      if (i == 0) {
        radian = .6 * pi;
        print(50 * 4 * pow(sin(0.3 * pi), 2) * cos(0.1 * pi));
      } else if (i.isEven) {
        radian += 1.2 * pi;
      } else {
        radian += 0.4 * pi;
      }
      x += step * cos(radian);
      y += step * sin(radian);
      path.lineTo(x, y);
    }
    return path;
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
    return false;
  }
}

Upvotes: 0

Hairy Ass
Hairy Ass

Reputation: 338

This is my version, can specify rotation, and color

class TrianglePainter extends CustomPainter {
  double sideSize;

  Color color;
  TrianglePainter({required this.sideSize, required this.color});

  @override
  void paint(Canvas canvas, Size size) {
    double ySize = sideSize * cos(30 * pi / 180);
    double xSize = sideSize;

    double point0x = xSize / 2;
    double point0y = ySize / 2;

    double point1x = -xSize / 2;
    double point1y = ySize / 2;

    double point2x = 0;
    double point2y = -ySize / 2;

    Path path = Path();
    path.moveTo(point0x, point0y);
    path.lineTo(point1x, point1y);
    path.lineTo(point2x, point2y);
    path.lineTo(point0x, point0y);
    path.close();
    canvas.drawPath(
        path,
        Paint()
          ..color = color
          ..style = PaintingStyle.fill);

    canvas.save();
    canvas.restore();
  }

  @override
  bool shouldRepaint(TrianglePainter oldDelegate) {
    return oldDelegate.color != color || oldDelegate.sideSize != sideSize;
  }
}

Widget triangle(double sideSize, Color color, double angle) {
  return Transform.rotate(
      child: CustomPaint(
        painter: TrianglePainter(
          color: color,
          sideSize: sideSize,
        ),
      ),
      angle: angle * pi / 180);
}

Upvotes: 0

mohammad
mohammad

Reputation: 2910

create CustomClipper

class CustomTriangleClipper extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    final path = Path();
    path.lineTo(size.width, 0);
    path.lineTo(size.width, size.height);
    path.lineTo(0, 0);
    return path;
  }

  @override
  bool shouldReclip(CustomClipper<Path> oldClipper) {
    return false;
  }
}

and then Usage :

ClipPath(
    clipper: CustomTriangleClipper(),
    child: Container(
      width: 50,
      height: 50,
      decoration: BoxDecoration(
        gradient: LinearGradient(
          begin: Alignment.bottomLeft,
          end: Alignment.topRight,
          colors: [Color(0xffF25D50), Color(0xffF2BB77)],
        ),
      ),
    ),
  );

Upvotes: 13

Jigar
Jigar

Reputation: 431

Below is the code which you can refer.

class MyButton extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    Offset centerPoint = Offset(100, 100);
    double radius = 60;
    double triangleA = 35;   // this the dimension of triangle's side
    double triangleR = triangleA / sqrt(3.0);   // this the distance between the center of triangle/circle to corner of triangle

    // I am drawing here circle, while you can draw your shape as per your convenience.
    canvas.drawCircle(
        centerPoint,
        radius,
        Paint()
          ..color = Colors.grey[700]
          ..style = PaintingStyle.fill);

    Path path = Path();

    double x1Point = centerPoint.dx + triangleR * cos(3 * pi / 2);
    double y1Point = centerPoint.dy + triangleR * sin(3 * pi / 2);
    path.moveTo(x1Point, y1Point);

    double x2Point = centerPoint.dx +
        triangleR * cos((3 * pi / 2) - Angle.fromDegrees(120).radians);
    double y2Point = centerPoint.dy +
        triangleR * sin((3 * pi / 2) - Angle.fromDegrees(120).radians);
    path.lineTo(x2Point, y2Point);

    double x3Point = centerPoint.dx +
        triangleR * cos((3 * pi / 2) + Angle.fromDegrees(120).radians);
    double y3Point = centerPoint.dy +
        triangleR * sin((3 * pi / 2) + Angle.fromDegrees(120).radians);
    path.lineTo(x3Point, y3Point);

    path.close();

    canvas.drawPath(
        path,
        Paint()
          ..color = Colors.deepOrange
          ..style = PaintingStyle.fill);

    canvas.save();
    canvas.restore();
  }
RawMaterialButton(
 child: CustomPaint(
   painter: MyButton(),
   child: GestureDetector(
     onTap: () {
        print('Here, you can handle button click event');
     },
   ),
 ),
 onPressed: () {
 },
)

Upvotes: 1

Ajil O.
Ajil O.

Reputation: 6892

You can do it by creating your own custom painter implementation.

Triangle Painter

class TrianglePainter extends CustomPainter {
  final Color strokeColor;
  final PaintingStyle paintingStyle;
  final double strokeWidth;

  TrianglePainter({this.strokeColor = Colors.black, this.strokeWidth = 3, this.paintingStyle = PaintingStyle.stroke});

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = strokeColor
      ..strokeWidth = strokeWidth
      ..style = paintingStyle;

    canvas.drawPath(getTrianglePath(size.width, size.height), paint);
  }

  Path getTrianglePath(double x, double y) {
    return Path()
      ..moveTo(0, y)
      ..lineTo(x / 2, 0)
      ..lineTo(x, y)
      ..lineTo(0, y);
  }

  @override
  bool shouldRepaint(TrianglePainter oldDelegate) {
    return oldDelegate.strokeColor != strokeColor ||
        oldDelegate.paintingStyle != paintingStyle ||
        oldDelegate.strokeWidth != strokeWidth;
  }
}

USAGE

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: RawMaterialButton(
          onPressed: () {},
          child: CustomPaint(
            painter: TrianglePainter(
              strokeColor: Colors.blue,
              strokeWidth: 10,
              paintingStyle: PaintingStyle.fill,
            ),
            child: Container(
              height: 180,
              width: 200,
            ),
          ),
        ),
      ),
    );
  }
}

Upvotes: 41

Related Questions