Flutter DataTable Layout
Step 1:
Future<List<NameData>> generateList() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/posts');
var list = await json.decode(response.body).cast<Map<String, dynamic>>();
return await list.map<NameData>((json) => NameData.fromJson(json)).toList();
}
Step 2:
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('DataTable'),
),
body: Container(
child: FutureBuilder<List<NameData>>(
future: generateList(),
builder: (context, snapShot) {
if (snapShot.hasData) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: <DataColumn>[
DataColumn(
label: Text(
'First Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Last Name',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: snapShot.data.map<DataRow>((e) {
return DataRow(
cells: <DataCell>[
DataCell(Text('${e.id}')),
DataCell(Text('${e.userId}')),
DataCell(Icon(Icons.delete)),
],
);
}).toList(),
),
);
}else{
return CircularProgressIndicator();
}
},
)),
),
);
}
GrandMagus
Updated on December 27, 2022Comments
-
GrandMagus over 1 year
I've got some layout trouble with
DataTable
in Flutter with aFutureBuilder
, I've called the API and naturally it will display it like this:Understandable, since I'm building a list of tables it will return multiple tables back. I want to map out only the Rows as a List and the columns should stay the same, exactly like this:
So, the columns
First Name
,Last Name
andDelete
are always the same, it just maps out the table row cells like in the second picture above.Is this possible to achieve this with a
DataTable
using theFutureBuilder
like in my example?I've tried using the future builder in a
DataRow
cell since every child of theDataCell
is a Widget, but it looks really horrible and I'm not sure it is the right practice...Here is the code:
The API call:
import 'dart:async'; import 'dart:convert'; import 'package:http/http.dart' as http; import 'models/names.dart'; Future<List<NameData>> fetchNames() async { List<NameData> names = List(); final response = await http.get('https://jsonplaceholder.typicode.com/posts'); if (response.statusCode == 200) { // If the server did return a 200 OK response, // then parse the JSON. var namesJson = jsonDecode(response.body); print(response.body); for (int i = 0; i < namesJson.length; i++) { names.add(NameData.fromJson(jsonDecode(response.body)[i])); } return names; } else { // If the server did not return a 200 OK response, // then throw an exception. throw Exception('Failed to load names'); } }
The Names model:
import 'package:flutter/foundation.dart'; import 'dart:core'; class NameData extends ChangeNotifier { final int id; final int userId; final String title; final String body; NameData({ this.id, this.userId, this.title, this.body, }); factory NameData.fromJson(Map<String, dynamic> json) { return NameData( id: json["id"], userId: json["userId"], title: json["title"], body: json["body"], ); } }
And the Names List with the Data table:
import 'package:flutter/material.dart'; import 'models/names.dart'; import 'services/name_api.dart'; class NameList extends StatefulWidget { @override _NameList createState() => _NameList(); } class _NameList extends State<NameList> { Future<List<NameData>> futureNames; @override void initState() { super.initState(); futureNames = fetchNames(); } @override Widget build(BuildContext context) { return Column( children: [ SizedBox( height: 600, child: FutureBuilder<List<NameData>>( future: futureNames, builder: (context, snapshot) { if (snapshot.hasData) { return ListView.builder( itemCount: snapshot.data.length, itemBuilder: (context, index) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ SizedBox( height: 12.0, ), Container( decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.all( Radius.circular(12.0), ), ), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: DataTable( columns: <DataColumn>[ DataColumn( label: Text( 'First Name', style: TextStyle(fontStyle: FontStyle.italic), ), ), DataColumn( label: Text( 'Last Name', style: TextStyle(fontStyle: FontStyle.italic), ), ), DataColumn( label: Text( 'Delete', style: TextStyle(fontStyle: FontStyle.italic), ), ), ], rows: <DataRow>[ DataRow( cells: <DataCell>[ DataCell( Text('${snapshot.data[index].id}')), DataCell( Text('${snapshot.data[index].userId}')), DataCell(Icon(Icons.delete)), ], ), ], ), ), ), SizedBox( height: 16.0, ), ], ); }, ); } else if (snapshot.hasError) { return Text("${snapshot.error}"); } return Container(); }, ), ), ], ); } }
Thank you in advance for your time and help.
-
GrandMagus over 3 yearsThank you! For reference, you solution was right on point but it still returns another table, but your answer made me realize my mistake, i just need to put the
itemCount
to1
! :) Thanks again!