Flutter自定义渲染插件render_box_exposed的使用

Flutter自定义渲染插件render_box_exposed的使用

简介

render_box_exposed 是一个 Flutter 包,用于暴露一个 Widget 的 RenderBox

开始使用

首先,将该包添加到你的 Flutter 项目中:

dependencies:
  render_box_exposed: ^1.1.0

然后运行 flutter pub get 来获取依赖。

属性

RenderBoxExposer

  • isExposed: 如果 RenderBox 已被暴露,则为 true,否则为 false
  • renderBox: 一个 ValueNotifier<RenderBox?>,用于通知暴露的 RenderBox。在第一次构建完成之前,value 属性为 null
bool isExposed;

ValueNotifier<RenderBox?> renderBox;

使用方法

要使用 RenderBoxExposed 类来包裹你选择的 Widget,并暴露其 RenderBox

final RenderBoxExposer exposer = const RenderBoxExposer();

[@override](/user/override)
Widget build(BuildContext context) {
    return Center(
        child: RenderBoxExposed(
            exposer: exposer,
            child: Text("Hey!"),
        ),
    );
}

最后,使用 RenderBoxExposer 包裹类来获取 RenderBox 对象。在第一次构建完成后,通过条件逻辑检查值是否可用。

// 不好的做法(renderBox 在第一次构建时可能为 null)
double width = exposer.renderBox.value!.size.width;

// 好的做法
if (exposer.isExposed) {
    double width = exposer.renderBox.value!.size.width;
}

注意:从版本 1.1.0 及以上,你可以直接使用 ValueListenableBuilder 订阅 notifier 属性。

完整示例

final RenderBoxExposer exposer = const RenderBoxExposer();

[@override](/user/override)
Widget build(BuildContext context) {
    return Center(
        child: Column(
            children: [
                RenderBoxExposed(
                    exposer: exposer,
                    child: Text("Hey!"),
                ),
                ValueListenableBuilder(
                    valueListenable: exposer.renderBox,
                    builder: (ctx, renderBox, c) {
                        if (exposer.isExposed) {
                            return Text("Width: ${renderBox!.size.width}");
                        } else {
                            return const Text("");
                        }
                    }
                ),
            ],
        ),
    );
}

示例代码

以下是完整的示例代码,展示了如何使用 render_box_exposed 包来动态更新文本大小并显示 RenderBox 的高度。

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

void main() {
  runApp(const MaterialApp(home: HomePage()));
}

class HomePage extends StatefulWidget {
  const HomePage({super.key});

  [@override](/user/override)
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with SingleTickerProviderStateMixin {
  late final RenderBoxExposer textExposer;
  late final AnimationController controller;

  double textSize = 10;

  [@override](/user/override)
  void initState() {
    super.initState();

    textExposer = RenderBoxExposer();

    controller = AnimationController(vsync: this, duration: const Duration(seconds: 1));
    Animation<int> tween = IntTween(begin: 10, end: 35).animate(controller);
    tween.addListener(() => setState(() => textSize = tween.value.toDouble()));

    controller.repeat(reverse: true);
  }

  [@override](/user/override)
  void dispose() {
    controller.dispose();
    super.dispose();
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: ValueListenableBuilder(
          valueListenable: textExposer.renderBox,
          builder: ((context, value, child) {
            if (value != null) {
              return Text("Height: ${value.size.height}");
            } else {
              return const Text("RenderBoxExposed");
            }
          }),
        ),
        centerTitle: true,
      ),
      body: Center(
        child: RenderBoxExposed(
          exposer: textExposer,
          child: Text("Sample text", style: TextStyle(fontSize: textSize)),
        ),
      ),
    );
  }
}

更多关于Flutter自定义渲染插件render_box_exposed的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter自定义渲染插件render_box_exposed的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,关于如何在Flutter中使用自定义渲染插件render_box_exposed,这里是一个具体的代码案例来展示其基本用法。render_box_exposed插件允许开发者更深入地控制和自定义渲染逻辑,类似于直接使用底层的RenderBox类。

首先,确保你已经在pubspec.yaml文件中添加了render_box_exposed依赖:

dependencies:
  flutter:
    sdk: flutter
  render_box_exposed: ^最新版本号  # 请替换为实际可用的最新版本号

然后,运行flutter pub get来安装依赖。

接下来,我们将创建一个自定义的RenderBox并使用render_box_exposed来渲染它。这个示例将创建一个简单的自定义渲染框,它会绘制一个带有边框的矩形。

1. 创建一个自定义RenderBox

import 'package:flutter/rendering.dart';
import 'package:render_box_exposed/render_box_exposed.dart';

class CustomRenderBox extends RenderBoxExposed {
  @override
  void paint(PaintingContext context, Offset offset) {
    final canvas = context.canvas;
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.fill;

    // 绘制矩形背景
    canvas.drawRect(offset & size, paint);

    // 绘制边框
    final borderPaint = Paint()
      ..color = Colors.black
      ..style = PaintingStyle.stroke
      ..strokeWidth = 4.0;
    canvas.drawRect(offset & size, borderPaint);
  }

  @override
  bool hitTestSelf(Offset position) => position.dx > 0 && position.dx < size.width &&
                                        position.dy > 0 && position.dy < size.height;
}

2. 使用自定义RenderBox

在Flutter的Widget树中使用这个自定义的RenderBox,可以通过一个自定义的LayoutBuilder来完成:

import 'package:flutter/material.dart';
import 'package:render_box_exposed/render_box_exposed.dart';
import 'custom_render_box.dart'; // 假设上面的代码保存在这个文件里

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Custom RenderBox Example'),
        ),
        body: Center(
          child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              return Container(
                width: constraints.maxWidth * 0.8,
                height: constraints.maxHeight * 0.6,
                child: CustomPaintExposed(
                  size: Size(constraints.maxWidth * 0.8, constraints.maxHeight * 0.6),
                  painter: (Canvas canvas) {
                    final renderBox = CustomRenderBox()
                      ..layout(constraints, parentUsesSize: true)
                      ..paint(null, Offset.zero);
                    // 这里实际上不需要再次调用paint,因为RenderBox已经完成了绘制,
                    // 但为了展示如何使用Canvas,我们假设直接在这里绘制(实际上是不必要的)。
                    // 正确的做法是让Flutter框架管理RenderBox的生命周期和绘制。
                    // 在实际使用中,你会将CustomRenderBox添加到RenderTree中。
                  },
                ),
              );
            },
          ),
        ),
      ),
    );
  }
}

注意:上面的代码示例中,CustomPaintExposed和直接调用CustomRenderBoxpaint方法并不是render_box_exposed插件的标准用法,而是为了展示如何定义和使用自定义的RenderBox。在实际应用中,你应该将自定义的RenderBox添加到RenderTree中,而不是在CustomPaint的painter回调中直接实例化它。

正确的做法是将自定义的RenderBox封装在一个SingleChildRenderObjectWidget中,如下所示:

3. 封装自定义RenderBox为Widget

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'custom_render_box.dart'; // 假设上面的代码保存在这个文件里

class CustomRenderBoxWidget extends SingleChildRenderObjectWidget {
  @override
  RenderObject createRenderObject(BuildContext context) {
    return CustomRenderBox();
  }

  @override
  void updateRenderObject(BuildContext context, RenderObject renderObject) {
    // 在这里可以更新RenderObject的状态,如果有需要的话
  }
}

然后在Widget树中使用这个封装好的Widget:

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('Custom RenderBox Example'),
        ),
        body: Center(
          child: LayoutBuilder(
            builder: (BuildContext context, BoxConstraints constraints) {
              return SizedBox(
                width: constraints.maxWidth * 0.8,
                height: constraints.maxHeight * 0.6,
                child: CustomRenderBoxWidget(),
              );
            },
          ),
        ),
      ),
    );
  }
}

这样,你的自定义RenderBox就被正确地集成到了Flutter的Widget树中,并且可以正确地布局和渲染。

回到顶部