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?
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?'
CodePudding user response:
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)); //// <---------------------
});
}
},
),
))
);
}
CodePudding user response:
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));
}
CodePudding user response:
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??''));
});
CodePudding user response:
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));
});
}