GoodMan
GoodMan

Reputation: 650

The return type 'Person' isn't a 'Widget', as required by the closure's context

I am a new Flutter learner and try some code snippets on dartpad.dev to work around and see how do they work. This is a code I recently wrote but I don't know why it doesn't work?

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: MyWidget(),
        ),
      ),
    );
  }
}

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Map<String, Object> x = {};

    x.putIfAbsent('Jack', () => Person(name: "Jack", age: 10));
    x.putIfAbsent('Joe', () => Person(name: "Joe", age: 10));

    return Container(
      child: ListView.builder(
          itemBuilder: (context, index) => Person(
              x.values.toList()[index].name, x.values.toList()[index].age),
          itemCount: x.length),
    );
  }
}

class Person {
  String? name;
  int? age;

  Person({
    this.name,
    this.age,
  });
}

This is the Error I see on dartpad.dev:

The return type 'Person' isn't a 'Widget', as required by the closure's context.

Upvotes: 1

Views: 3512

Answers (1)

gbaccetta
gbaccetta

Reputation: 4577

you have to understand the way flutter works which is based around Widgets. Widgets are component that are put in a tree like structure in a logic of parent and children.

Person is a simple class you have created with two fields but it is not a Widget that can be used in the UI.

The UI tree you are building include a ListWidget that want to build a list of Widgets.

The builder hence expect a Widget, not a Person. You can use the Person to build the Widget though or transform your Person class into a stateless Widget.

I suggest you start reading here: https://docs.flutter.dev/development/ui/widgets-intro

To make your code works with a minimum adjustment you can try using a Text Widget in which you pass your Person details:

return Container(
  child: ListView.builder(
      itemBuilder: (context, index) => Text(
          '${x.values.toList()[index].name}, ${x.values.toList()[index].age}'),
      itemCount: x.length),

If instead you Transform Person into a Widget you have to make person extends a StelessWidget as follow. This way your Person class will have a build method that describe as that Widget should be built into the UI. The result will be the same.

import 'package:flutter/material.dart';
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            body: Center(
              child: MyWidget(),
            ),
          ),
        );
      }
    }
    
    class MyWidget extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        Map<String, Object> x = {};
    
        x.putIfAbsent('Jack', () => Person(name: "Jack", age: 10));
        x.putIfAbsent('Joe', () => Person(name: "Joe", age: 10));
    
        return Container(
          child: ListView.builder(
              itemBuilder: (context, index) => x.values.toList()[index],
              itemCount: x.length),
        );
      }
    }
    
    class Person extends StatelessWidget {
      String? name;
      int? age;
    
      Person({
        this.name,
        this.age,
      });
    
      @override
      Widget build(BuildContext context) {
      return Text('$name, $age');
      }
    }

Upvotes: 1

Related Questions