3

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?'
1
  • 2
    Your ListTile widget accepts Widget or null for a title, and you are passing a String to it. Commented Dec 29, 2022 at 7:46

4 Answers 4

2

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)); //// <---------------------
                    });
              }
            },
          ),
    ))
    );
  }
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for that. I was so stuck without hope
1

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));
}

Comments

1

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??''));
                });

Comments

1

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));
                });
          }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.