dengyin2000 / dynamic_widget

A Backend-Driven UI toolkit, build your dynamic UI with json, and the json format is very similar with flutter widget code.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Widget fails to render when a Stack widget is used

loongyeat opened this issue · comments

As title implies. Console shows flutter: Null check operator used on a null value. To re-create:

class SomeWidget extends StatelessWidget {
  const SomeWidget({Key? key}) : super(key: key);

  static final _key = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          final exporter = _key.currentWidget as DynamicWidgetJsonExportor?;
          final exportedJsonString = exporter?.exportJsonString();

          if (exportedJsonString == null) {
            return;
          }

          Navigator.of(context).push<void>(
            MaterialPageRoute(
              builder: (context) => const RendererWidget(exportedJsonString),
            ),
          );
        },
        child: const Icon(Icons.copy),
      ),
      body: DynamicWidgetJsonExportor(
        key: _key,
        child: _buildSimpleWidget(),
      ),
    );
  }

  Widget _buildSimpleWidget() {
    return Stack(
      children: [
        Icon(Icons.star),
        Icon(Icons.abc),
      ],
    );
  }
}

class RendererWidget extends StatelessWidget {
  const RendererWidget(this.json, {Key? key}) : super(key: key);

  final String json;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(),
      body: SafeArea(
        child: FutureBuilder<Widget?>(
          future: _buildWidget(context),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              print(snapshot.error);
            }

            if (!snapshot.hasData) {
              return Container();
            }

            return SizedBox.expand(
              child: snapshot.data,
            );
          },
        ),
      ),
    );
  }

  Future<Widget?> _buildWidget(BuildContext context) async {
    return Future.delayed(const Duration(seconds: 1), () {
      return DynamicWidgetBuilder.build(
        json,
        context,
        DefaultClickListener(),
      );
    });
  }
}

class DefaultClickListener implements ClickListener {
  @override
  void onClicked(String? event) {
    print(event);
  }
}

As title implies. Console shows flutter: Null check operator used on a null value. To re-create:

class SomeWidget extends StatelessWidget {
  const SomeWidget({Key? key}) : super(key: key);

  static final _key = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          final exporter = _key.currentWidget as DynamicWidgetJsonExportor?;
          final exportedJsonString = exporter?.exportJsonString();

          if (exportedJsonString == null) {
            return;
          }

          Navigator.of(context).push<void>(
            MaterialPageRoute(
              builder: (context) => const RendererWidget(exportedJsonString),
            ),
          );
        },
        child: const Icon(Icons.copy),
      ),
      body: DynamicWidgetJsonExportor(
        key: _key,
        child: _buildSimpleWidget(),
      ),
    );
  }

  Widget _buildSimpleWidget() {
    return Stack(
      children: [
        Icon(Icons.star),
        Icon(Icons.abc),
      ],
    );
  }
}

class RendererWidget extends StatelessWidget {
  const RendererWidget(this.json, {Key? key}) : super(key: key);

  final String json;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(),
      body: SafeArea(
        child: FutureBuilder<Widget?>(
          future: _buildWidget(context),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              print(snapshot.error);
            }

            if (!snapshot.hasData) {
              return Container();
            }

            return SizedBox.expand(
              child: snapshot.data,
            );
          },
        ),
      ),
    );
  }

  Future<Widget?> _buildWidget(BuildContext context) async {
    return Future.delayed(const Duration(seconds: 1), () {
      return DynamicWidgetBuilder.build(
        json,
        context,
        DefaultClickListener(),
      );
    });
  }
}

class DefaultClickListener implements ClickListener {
  @override
  void onClicked(String? event) {
    print(event);
  }
}

I try your code, it seems it's ok. the "exportedJsonString" is

exportedJsonString: {"type":"Stack","alignment":"topStart","textDirection":"ltr","fit":"loose","clipBehavior":"hardEdge","children":[{"type":"Icon","data":"star","size":null,"color":null,"semanticLabel":null,"textDirection":null},{"type":"Icon","data":"ac_unit","size":null,"color":null,"semanticLabel":null,"textDirection":null}]}