【问题标题】:How to use ClipPath to get this type of design layout?如何使用 ClipPath 来获得这种类型的设计布局?
【发布时间】:2021-11-21 01:29:41
【问题描述】:

我一直在摸索很长一段时间,只是为了获得这种类型的 TextFormField 设计布局,但失败了!

TextFormField

注意反海峡线。我在 Internet 上对该布局的进一步搜索得出的结论是,我可以使用自定义剪辑器或剪辑路径来归档这种类型的布局。但我只是一个学习颤振的初学者,以前从未使用过自定义剪裁器,我不知道如何使用它。请帮忙。

【问题讨论】:

    标签: flutter layout clipper flutter-clippath


    【解决方案1】:

    我认为您可以使用 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;
    }
    

    这里是 CustomPainter 基础知识的链接:link


    更新:

    这是显示 TextField 的小部件的书面代码,当然还有您的自定义形状:

    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;
    }
    

    您只需对密码 TextField 执行相同操作即可。

    这是它的外观:

    【讨论】:

    • 我越想了解CustomClipper/CustomPainter,它就越复杂。仍然无法做出这样的设计。
    • @SiddharthMehra 我完全理解,当我第一次发现它时,它让我有些头疼。今晚我会尽力为你做这个UI,如果我不忘记我会在这里发布!
    • @SiddharthMehra 完成了
    • 哇!太感谢了。非常感谢您的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多