Flutter 自定义控件开发实例

我正在学习Flutter的自定义控件开发,但遇到了一些困难。能否分享一个完整的自定义控件开发实例?比如如何从零开始创建一个自定义的按钮或图表控件,需要继承哪个基类?在绘制过程中应该使用CustomPainter还是直接继承RenderObject?性能优化方面有哪些需要注意的地方?最好能包含布局测量、绘制逻辑和手势处理的完整代码示例。另外,自定义控件如何适应不同的屏幕尺寸和主题风格?

3 回复

作为一个屌丝程序员,我来分享一个简单的 Flutter 自定义控件实例。

比如我们要创建一个带圆角的点击按钮。首先定义一个类继承自 StatelessWidget

class RoundButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;

  RoundButton({required this.text, required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return Container(
      decoration: BoxDecoration(
        color: Colors.blue,
        borderRadius: BorderRadius.circular(16),
      ),
      child: TextButton(
        onPressed: onPressed,
        child: Text(
          text,
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}

使用时直接 RoundButton(text: '点击我', onPressed: () { print('按钮被点击了'); }); 即可。

这个例子展示了如何通过组合现有控件(Container 和 TextButton)来自定义一个带有圆角的按钮。屌丝程序员不需要复杂的东西,实用就好!

更多关于Flutter 自定义控件开发实例的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


下面是一个简单的 Flutter 自定义控件实例:

  1. 创建一个自定义圆形按钮:
class RoundButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;

  RoundButton({required this.text, required this.onPressed});

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: BorderRadius.circular(50),
      child: MaterialButton(
        padding: EdgeInsets.symmetric(vertical: 12, horizontal: 24),
        color: Colors.blue,
        onPressed: onPressed,
        child: Text(
          text,
          style: TextStyle(color: Colors.white),
        ),
      ),
    );
  }
}
  1. 在页面中使用:
class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('自定义控件示例')),
      body: Center(
        child: RoundButton(
          text: '点击我',
          onPressed: () {
            print('按钮被点击了');
          },
        ),
      ),
    );
  }
}

这个例子中,我们创建了一个带有圆角的按钮控件,并可以在任何地方复用。

Flutter 自定义控件开发实例

在Flutter中,自定义控件通常是通过组合现有Widget或创建全新的RenderObject来实现的。以下是几种常见的自定义控件开发方式:

1. 通过组合现有Widget

这是最简单的方式,通过组合已有的Widget来创建新控件:

class CustomButton extends StatelessWidget {
  final String text;
  final VoidCallback onPressed;
  
  const CustomButton({
    required this.text,
    required this.onPressed,
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      style: ElevatedButton.styleFrom(
        padding: EdgeInsets.symmetric(horizontal: 30, vertical: 15),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(30),
        ),
      ),
      onPressed: onPressed,
      child: Text(
        text,
        style: TextStyle(fontSize: 18),
      ),
    );
  }
}

2. 使用CustomPaint绘制自定义图形

class CircleProgress extends CustomPainter {
  final double progress;
  
  CircleProgress(this.progress);

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = Colors.grey
      ..style = PaintingStyle.stroke
      ..strokeWidth = 10;

    canvas.drawCircle(size.center(Offset.zero), size.width/2, paint);
    
    final progressPaint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = 10
      ..strokeCap = StrokeCap.round;

    canvas.drawArc(
      Rect.fromCircle(center: size.center(Offset.zero), radius: size.width/2),
      -pi/2,
      2 * pi * progress,
      false,
      progressPaint,
    );
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

// 使用方式
CustomPaint(
  painter: CircleProgress(0.7),
  size: Size(100, 100),
)

3. 自定义RenderObject (高级)

对于更复杂的自定义控件,可能需要直接继承RenderObject:

class CustomRenderBox extends RenderBox {
  @override
  void performLayout() {
    size = constraints.biggest;
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;
    canvas.save();
    canvas.translate(offset.dx, offset.dy);
    
    // 自定义绘制逻辑
    final paint = Paint()..color = Colors.red;
    canvas.drawCircle(Offset(size.width/2, size.height/2), 30, paint);
    
    canvas.restore();
  }
}

// 使用RenderObjectWidget包装
class CustomWidget extends SingleChildRenderObjectWidget {
  @override
  RenderObject createRenderObject(BuildContext context) => CustomRenderBox();
}

选择哪种方式取决于你的需求。对于大多数情况,组合现有Widget或使用CustomPaint就足够了,只有需要极致性能或特殊布局时才需要直接操作RenderObject。

回到顶部