自定义 Widget

自定义 Widget 用于创建满足特定需求的组件,包括简单的组合到复杂的渲染。

提示:根据需求选择合适的自定义 Widget 方式。
📱 渲染效果预览

RenderObject

RenderObject 是 Flutter 渲染的核心,处理布局和绘制。

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

  @override
  void paint(PaintingContext context, Offset offset) {
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;
    context.canvas.drawRect(
      Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height),
      paint,
    );
  }
}
📱 渲染效果预览
自定义卡片
这是一个组合现有Widget的自定义组件

Custom Widget

通过组合现有 Widget 创建自定义组件。

class CustomCard extends StatelessWidget {
  final String title;
  final String subtitle;
  final VoidCallback? onTap;

  const CustomCard({
    required this.title,
    required this.subtitle,
    this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    return Card(
      elevation: 4,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
      ),
      child: InkWell(
        onTap: onTap,
        borderRadius: BorderRadius.circular(12),
        child: Padding(
          padding: EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: Theme.of(context).textTheme.titleLarge,
              ),
              SizedBox(height: 8),
              Text(
                subtitle,
                style: Theme.of(context).textTheme.bodyMedium,
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Custom Sliver

创建自定义 Sliver 组件用于滚动效果。

class CustomSliverHeader extends SingleChildRenderObjectWidget {
  final double height;
  final Color color;

  const CustomSliverHeader({
    required this.height,
    required this.color,
    Widget? child,
  }) : super(child: child);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return _RenderCustomSliverHeader(height, color);
  }

  @override
  void updateRenderObject(
    BuildContext context,
    _RenderCustomSliverHeader renderObject,
  ) {
    renderObject.height = height;
    renderObject.color = color;
  }
}

class _RenderCustomSliverHeader extends RenderSliverSingleBoxAdapter {
  double height;
  Color color;

  _RenderCustomSliverHeader(this.height, this.color);

  @override
  double get maxChildExtent => height;

  @override
  double get minChildExtent => height;
}
📱 渲染效果预览

RenderObjectWidget

RenderObjectWidget 是创建自定义渲染 Widget 的基类。

class MyCustomWidget extends LeafRenderObjectWidget {
  final Color color;
  final double size;

  const MyCustomWidget({
    required this.color,
    required this.size,
  });

  @override
  RenderObject createRenderObject(BuildContext context) {
    return _MyCustomRenderObject(color, size);
  }

  @override
  void updateRenderObject(
    BuildContext context,
    _MyCustomRenderObject renderObject,
  ) {
    renderObject.color = color;
    renderObject.size = size;
  }
}

class _MyCustomRenderObject extends RenderBox {
  Color color;
  double size;

  _MyCustomRenderObject(this.color, this.size);

  @override
  void performLayout() {
    size = Size.square(this.size);
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    final paint = Paint()..color = color;
    context.canvas.drawCircle(offset, size.width / 2, paint);
  }
}
📱 渲染效果预览
1
2
3
4
5
6

MultiChildRenderObject

MultiChildRenderObject 用于创建具有多个子组件的自定义 Widget。

class MyCustomLayout extends MultiChildRenderObjectWidget {
  MyCustomLayout({
    List children = const [],
  }) : super(children: children);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return _MyCustomLayoutRenderObject();
  }
}

class _MyCustomLayoutRenderObject extends RenderBox
    with ContainerRenderObjectMixin,
         RenderBoxContainerDefaultsMixin {
  @override
  void setupParentData(RenderBox child) {
    if (child.parentData is! _MyCustomLayoutParentData) {
      child.parentData = _MyCustomLayoutParentData();
    }
  }

  @override
  void performLayout() {
    size = constraints.biggest;
    // 自定义布局逻辑
  }

  @override
  void paint(PaintingContext context, Offset offset) {
    // 自定义绘制逻辑
    defaultPaint(context, offset);
  }
}

class _MyCustomLayoutParentData extends ContainerBoxParentData {}
自定义 Widget 最佳实践:
  • 优先组合现有 Widget
  • 只在必要时创建 RenderObject
  • 正确处理约束和尺寸
  • 实现 hitTest 支持交互
  • 优化重绘和布局