skip to Main Content

I am new to Flutter.
I made a flutter project that gets data from an API and displays them in a ListView.
And if no data in snapShot then shows a loading screen.

I got an error when I ran the program after fixing some small errors.

Error : type ‘String’ is not a subtype of type ‘Widget?

enter image description here

My Code:

import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

class DataFromAPI extends StatefulWidget {
  const DataFromAPI({Key? key}) : super(key: key);

  @override
  State<DataFromAPI> createState() => _DataFromAPIState();
}

class _DataFromAPIState extends State<DataFromAPI> {

  getUserData() async{
    var response = await http.get(Uri.parse('https://jsonplaceholder.typicode.com/users'));
    var jsonData = jsonDecode(response.body);
    print(response.body);
    List<User> users = [];

    for(var u in jsonData){
      User user = User(u['name'],u['email'],u['username']);
      users.add(user);
    }
    //print(users.length);
    return users;
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Get Data From API'),
      ),
      body: Container(
        child: Card(
          child: FutureBuilder(
            future: getUserData(),
            builder: (context, AsyncSnapshot snapShot){
              if(snapShot.data == null){
                return Container(child: Center(child: Text('Loading'),),);
              }else{
                return ListView.builder(
                    itemCount: snapShot.data.length,
                    itemBuilder: (context, i){
                      return ListTile(title: snapShot.data[i].name);
                    });
              }
            },
          ),
    ))
    );
  }
}

class User{
  final String name, email, userName;
  User(this.name, this.email, this.userName);
}

Console Output:

Syncing files to device sdk gphone64 x86 64...
Reloaded 0 libraries in 506ms (compile: 12 ms, reload: 0 ms, reassemble: 433 ms).
D/EGL_emulation( 6751): app_time_stats: avg=8895.54ms min=975.35ms max=16815.74ms count=2

======== Exception caught by widgets library =======================================================
The following _TypeError was thrown building:
type 'String' is not a subtype of type 'Widget?'

4

Answers


  1. Your error comes from the fact that you are trying to create a ListTile widget and as the title you are passing in a String.

    But if you look at the documentation for ListTile, you can see that it expects the title to be a Text widget:

    Container(
      color: Colors.green,
      child: const Material(
        child: ListTile(
          title: Text('ListTile with red background'),
          tileColor: Colors.red,
        ),
      ),
    )
    

    So you need to change your code to this:

     @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Get Data From API'),
          ),
          body: Container(
            child: Card(
              child: FutureBuilder(
                future: getUserData(),
                builder: (context, AsyncSnapshot snapShot){
                  if(snapShot.data == null){
                    return Container(child: Center(child: Text('Loading'),),);
                  }else{
                    return ListView.builder(
                        itemCount: snapShot.data.length,
                        itemBuilder: (context, i){
                          return ListTile(title: const Text(snapShot.data[i].name)); //// <---------------------
                        });
                  }
                },
              ),
        ))
        );
      }
    
    Login or Signup to reply.
  2. You have to add widget to ListTile title, based on your requirements than you can assign text value to it.

    Here for string you can use Text widget

    itemBuilder: (context, i) {
         return ListTile(title: Text(snapShot.data[i].name));
    }
    
    Login or Signup to reply.
  3. List view title takes a widget, you need to pass a widget not a string that what you are doing right now.

    just wrap your title string in a Text widget.

    itemBuilder: (context, i){
                      return ListTile(title: Text(snapShot.data[i].name??''));
                    });
    
    Login or Signup to reply.
  4. Change your ListTile

    From

             return ListView.builder(
                    itemCount: snapShot.data.length,
                    itemBuilder: (context, i){
                      return ListTile(title: snapShot.data[i].name);
                    });
              }
    

    To

            return ListView.builder(
                    itemCount: snapShot.data.length,
                    itemBuilder: (context, i){
                      return ListTile(title: Text(snapShot.data[i].name));
                    });
              }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search