I am getting API data and it returns data of 5 arrays like this:
print('one: ${jsonResponse['one']}');
print('two: ${jsonResponse['two']}');
print('three: ${jsonResponse['three']}');
print('four: ${jsonResponse['four']}');
print('five: ${jsonResponse['five']}');
Each line is an array of data and all comes from single API URL.
My question is: how to divide this arrays in order to show them as separate block in my screen?
Code
This is what I have right now:
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
late Future myCards;
@override
void initState() {
super.initState();
myCards = getHome();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(12.0),
child: FutureBuilder(
future: myCards,
builder: (context, snapshot) {
if (snapshot.hasData) {
// require to separate arrays here
return Text('Hello!');
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
}
),
),
),
),
);
}
getHome() async {
var response = await http.get(
Uri.parse('https://example.com/api/home'),
headers: {
HttpHeaders.acceptHeader: 'application/json'
},
);
if (response.statusCode == 200) {
var jsonResponse = convert.jsonDecode(response.body) as Map<
String,
dynamic>;
if (kDebugMode) {
print('one: ${jsonResponse['one']}'); // returning array of data
print('two: ${jsonResponse['two']}'); // returning array of data
print('three: ${jsonResponse['three']}'); // returning array of data
print('four: ${jsonResponse['four']}'); // returning array of data
print('five: ${jsonResponse['five']}'); // returning array of data
}
return jsonResponse;
} else {
//
}
}
}
PS: Please feel free to suggest better approach if you have any in your mind, I'm open to all solutions.
Update
I've managed to get my data separately in my screen with code below
child: FutureBuilder(
future: myCards,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return Column(
children: [
//one
ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: snapshot.data['one'].length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.data['one'][index]['heading']),
],
);
}
),
//two
ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data['two'].length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.data['two'][index]['name']),
],
);
}
),
],
);
} else if (snapshot.hasError) {
return Center(child: Text('${snapshot.error}'));
}
// By default, show a loading spinner.
return const Center(child: CircularProgressIndicator());
}
),
But I'm facing following error:
RenderBox was not laid out: RenderRepaintBoundary#bc93a relayoutBoundary=up14 NEEDS-PAINT
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1979 pos 12: 'hasSize'
CodePudding user response:
if the scrollDirection of each list is vercital then this should solve the problem.
ListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: snapshot.data['one'].length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.data['one'][index]['heading']),
],
);
}
),
//two
ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data['two'].length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.data['two'][index]['name']),
],
);
}
),
But if one is horizontal you have to give it height.
example-->
SizedBox(
height: 200,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: snapshot.data['one'].length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.data['one'][index]['heading']),
],
);
}
)),
//two
ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data['two'].length,
itemBuilder: (BuildContext context, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(snapshot.data['two'][index]['name']),
],
);
}
)
CodePudding user response:
You could have sth like:
child: FutureBuilder<Map<String, dynamic>>(
future: myCards,
builder: (context, snapshot) {
if (snapshot.hasData) {
// Get your map from the snapshot
// If possible change "dynamic" to the specific type
final Map<String, dynamic> responseMap = snapshot.data!;
final List<Widget> children = [];
for(final key in responseMap.keys) {
// Considering the "dynamic" is a List of Strings
final List<String> response = responseMap[key];
// Iterate through each response
for(final item in response) {
// Build the widget for each item
children.add(Text(item));
}
}
// Use a Widget that can display a list of Widgets,
// such as ListView, PageView, Column
return Column(children:children);
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return const CircularProgressIndicator();
}
),