How to use ClipPath to get this type of design layout?

465 Views Asked by At

I have been scratching my head for a very long time just to get this type of design layout for a TextFormField but failed!

TextFormField

Notice the anti strait lines. My further search for this layout on the internet concludes that I can archive this type of layout using a custom clipper or clip-path. but I am just a beginner to learn flutter and never worked with custom clipper before, I have no idea how to use it. Please help.

1

There are 1 best solutions below

4
On BEST ANSWER

I think you can use a CustomPainter :

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(
        scaffoldBackgroundColor: darkBlue,
      ),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: CustomPaint(
            painter: MyPainter(),
            child: // your TextField with style so we don't see the borders etc...
          ),
        ),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
      // draw your rectangle from points here
  }

  // no need to repaint it because your shape is static
  @override
  bool shouldRepaint(Sky oldDelegate) => false;
  @override
  bool shouldRebuildSemantics(Sky oldDelegate) => false;
}

Here is the link for the basics of CustomPainter : link


UPDATE :

Here is the written code with the widget displaying the TextField and of course your custom shape :

class MainScreen extends StatefulWidget {
  @override
  _MainScreenState createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  // implementation of your custom active borders
  bool emailActive = false;
  FocusNode? emailNode;

  @override
  void initState() {
    super.initState();
    emailNode = FocusScopeNode()
      ..addListener(() {
        setState(() {
          emailActive = emailNode!.hasFocus;
        });
        print(emailActive);
      });
  }

  @override
  Widget build(BuildContext context) {
    final Size size = MediaQuery.of(context).size;
    final double width = size.width * 0.8;
    final double height = width * 0.15;

    return Scaffold(
      appBar: AppBar(
        title: Text('First screen'),
      ),
      body: Center(
        child: Container(
          height: height,
          width: width,
          child: Stack(
            children: [
              Center(
                // your shape
                child: CustomPaint(
                  painter: _TextFieldPainter(width, height, emailActive),
                ),
              ),
              Container(
                height: height,
                width: width,
                padding: const EdgeInsets.symmetric(horizontal: 10.0),
                child: Row(
                  children: [
                    Container(
                      width: 35,
                      padding: const EdgeInsets.only(
                          top: 5.0), // so it's aligned with the textfield
                      child: Icon(Icons.email_rounded),
                    ),
                    Container(
                      width: width - 35 - 20, // width - iconSize - padding
                      child: TextField(
                        decoration: InputDecoration(
                          hintText: 'Email id',
                          focusedBorder: InputBorder
                              .none, // so there is no border below the text field
                        ),
                        focusNode: emailNode,
                      ),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _TextFieldPainter extends CustomPainter {
  final double width;
  final double height;
  final bool active;

  _TextFieldPainter(this.width, this.height, this.active);

  @override
  void paint(Canvas canvas, Size size) {
    // The starting values so it's centered properly
    final double startX = width / -2;
    final double startY = height / -2;

    // Where you set the color etc...
    final Paint paint = Paint()
      ..color = active
          ? Colors.green
          : Colors.black // where you change the color wether it's active or not
      ..strokeWidth = 1.0;

    // Drawing the shape
    canvas.drawLine(
        Offset(startX, startY + 5.0), Offset(startX + width, startY), paint);
    canvas.drawLine(Offset(startX + width, startY),
        Offset(startX + width, startY + height), paint);
    canvas.drawLine(Offset(startX + width, startY + height),
        Offset(startX - 5.0, startY + height), paint);
    canvas.drawLine(Offset(startX - 5.0, startY + height),
        Offset(startX, startY + 5.0), paint);
  }

  // no need to repaint it here since there is no dynamic values
  @override
  bool shouldRepaint(_TextFieldPainter oldDelegate) => false;

  @override
  bool shouldRebuildSemantics(_TextFieldPainter oldDelegate) => false;
}

You just have to do the same for the password TextField.

And here is how it looks :

The requested result