I was using shared_preferences plugin in my Flutter application, I set my data when I click the button, but I try to get my data is not coming.
I set my data here and when I print it, I can see the output on my console.
shows.forEach((element) {
showCode=element.showName;
show.setString('showName', showCode);
});
I want to get my data here, above the override method. But when I print here, I just see 1 item, but I need to print 2 items.
String showCode;
Future<String> getCode() async{
final codeValue = await SharedPreferences.getInstance();
setState((){
showyCode =codeValue.getString('showName');
});
print('here $showCode');
return showCode;
}
But I cannot call this future in my function, even if I have 2 data to come but I just see 1 item. I tried to include it in Listview then it fills an entire list with 1 item. Anyone have an idea where I'm doing wrong?
_showProgramData
? Container(
height: MediaQuery.of(context).size.height/2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
IconButton(icon:Icon(Icons.close) , onPressed:() {Navigator.pushNamed(context, SecondScreen.routeName);}),
Text('Please Select Show',style: TextStyle(fontWeight:FontWeight.bold,fontSize: 24),),
],
),
Text(showCode),
],
),
),
)
You can copy paste run full code below
Step 1: You need to use setStringList and getStringList
Step 2: getCode() return Future<List<String>>
Step 3: In forEach use showCodeList.add(element.showName);
code snippet
void _setData() async {
shows.forEach((element) {
showCodeList.add(element.showName);
});
final codeValue = await SharedPreferences.getInstance();
await codeValue.setStringList('showName', showCodeList);
setState(() {});
}
Future<List<String>> getCode() async {
final codeValue = await SharedPreferences.getInstance();
showCodeList = await codeValue.getStringList('showName');
if (showCodeList == null) {
showCodeList = [];
}
print('here ${showCodeList.toString()}');
return showCodeList;
}
...
FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<List<String>> snapshot) {
...
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0, bottom: 6.0, left: 8.0, right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data[index]),
working demo
full code
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
final codeValue = await SharedPreferences.getInstance();
await codeValue.setStringList('showName', []);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class Show {
String showName;
Show({this.showName});
}
class _MyHomePageState extends State<MyHomePage> {
Future<List<String>> _future;
List<Show> shows = [Show(showName: "a"), Show(showName: "b")];
String showCode;
List<String> showCodeList = [];
void _setData() async {
shows.forEach((element) {
showCodeList.add(element.showName);
});
final codeValue = await SharedPreferences.getInstance();
await codeValue.setStringList('showName', showCodeList);
setState(() {});
}
Future<List<String>> getCode() async {
final codeValue = await SharedPreferences.getInstance();
showCodeList = await codeValue.getStringList('showName');
if (showCodeList == null) {
showCodeList = [];
}
print('here ${showCodeList.toString()}');
return showCodeList;
}
#override
void initState() {
_future = getCode();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: _future,
builder: (context, AsyncSnapshot<List<String>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0, bottom: 6.0, left: 8.0, right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data[index]),
],
),
));
});
}
}
}),
floatingActionButton: FloatingActionButton(
onPressed: _setData,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Related
am trying to call the user from data (am using firebase as database)
the profile page not working for more understanding check the other issue i posted last day :
FirebaseException ([cloud_firestore/unavailable] The service is currently unavailable , and how to solve it
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:yumor/models/progress.dart';
import 'package:yumor/models/user_model.dart';
class profile extends StatefulWidget {
const profile({Key? key,required this.userProfile}) : super(key: key);
final String? userProfile;
#override
State<profile> createState() => _profileState();
}
class _profileState extends State<profile> {
final userRef = FirebaseFirestore.instance.collection('users');
buildprofileheader() async{
final doc=await userRef.doc(widget.userProfile).get();
if(doc.exists){
var data=doc.data();
}
return FutureBuilder(future:FirebaseFirestore.instance.collection('users').doc(userRef.id).get(),
builder: ((context, snapshot) {
if(!snapshot.hasData){
return CircularProgress();
}
UserModel user=UserModel.fromMap(Map);
return Padding(padding:EdgeInsets.all(16.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.account_circle, size: 90,)
],
),
Container(
alignment: Alignment.center,
padding: EdgeInsets.all(12.0),
child: Text(
user.Username as String,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize:16.0,
),
),
),
],
),
);
}),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"Profile",
),
),
body: ListView(children: <Widget>[
buildprofileheader(), // the error shows in this line <=======
]));
}
}
Your buildprofileheader return type is Future<Widget> but it should be Widget in order to use in ListView, so you need to use an other FutureBuilder to get userRef. So just wrap your current FutureBuilder with an other one.
As for the logic part, you can simplify the logic for future method something like
Future<UserModel?> getData() async {
try{
final userRef = FirebaseFirestore.instance.collection('users');
final doc = await userRef.doc(widget.userProfile).get();
if (doc.exists) {
var data = doc.data(); // not sure about this use case
} else {
return null;
}
final data = await FirebaseFirestore.instance
.collection('users')
.doc(userRef.id)
.get();
if (data.exists) {
UserModel user = UserModel.fromMap(data);
return user;
}
} catch(e){ }
}
Create a state variable for future method , and use like
late final future = getData();
Widget buildprofileheader() {
return FutureBuilder<UserModel?>(
future: future,
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return CircularProgress();
}
return Padding(....
class _profileState extends State<profile> {
Future<UserModel?> getData() async {
final userRef = FirebaseFirestore.instance.collection('users');
final doc = await userRef.doc(widget.userProfile).get();
if (doc.exists) {
var data = doc.data(); // not sure about this use case
} else {
return null;
}
final data = await FirebaseFirestore.instance
.collection('users')
.doc(userRef.id)
.get();
if (data.exists) {
UserModel user = UserModel.fromMap(data);
return user;
}
}
late final future = getData();
Widget buildprofileheader() {
return FutureBuilder<UserModel?>(
future: future,
builder: ((context, snapshot) {
if (!snapshot.hasData) {
return CircularProgressIndicator();
}
return Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.account_circle,
size: 90,
)
],
),
Container(
alignment: Alignment.center,
padding: EdgeInsets.all(12.0),
child: Text(
user.Username as String,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
),
],
),
);
}),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"Profile",
),
),
body: ListView(children: <Widget>[
buildprofileheader(),
]));
}
}
I'm using api_cache_manager: ^1.0.2
How to get all cache?
Because i'm need all cache and showing in list
please someone help me
API Cache Manager is a Utility package built with Flutter SDK and
SQLite Package. This package will help to make your Rest API store in
the local db for offline access.
import
import 'package:api_cache_manager/api_cache_manager.dart';
import 'package:api_cache_manager/models/cache_db_model.dart';
import 'package:api_cache_manager/utils/cache_db_helper.dart';
This will provide all cached data
List<Map<String,dynamic>> list = await APICacheDBHelper.query(APICacheDBModel.table);
OR
List<Map<String,dynamic>> list =await APICacheDBHelper.rawQuery("select * from ${APICacheDBModel.table}");
This will create dummy data and save in cache and return all data from the cache
Future<List<Map<String, dynamic>>> fetchapiCach() async {
// await APICacheDBHelper.deleteAll(APICacheDBModel.table);
var lists = new List<int>.generate(10, (i) => i + 1);
lists.forEach((element) async {
var cacheData2 = await APICacheManager().addCacheData(new APICacheDBModel(
syncData: '{"name":"lava$element"}',
key: "$element",
));
});
List<Map<String,dynamic>> list = await APICacheDBHelper.query(APICacheDBModel.table);
// await APICacheDBHelper.rawQuery("select * from ${APICacheDBModel.table}");
return list;
}
SampleCode
import 'package:api_cache_manager/api_cache_manager.dart';
import 'package:api_cache_manager/models/cache_db_model.dart';
import 'package:api_cache_manager/utils/cache_db_helper.dart';
import 'package:flutter/material.dart';
void main() {
// fetchapiCach();
runApp(const MyApp());
}
Future<List<Map<String, dynamic>>> fetchapiCach() async {
// await APICacheDBHelper.deleteAll(APICacheDBModel.table);
var lists = new List<int>.generate(10, (i) => i + 1);
lists.forEach((element) async {
var cacheData2 = await APICacheManager().addCacheData(new APICacheDBModel(
syncData: '{"name":"lava$element"}',
key: "$element",
));
});
List<Map<String,dynamic>> list = await APICacheDBHelper.query(APICacheDBModel.table);
// await APICacheDBHelper.rawQuery("select * from ${APICacheDBModel.table}");
// print(list);
list.forEach((element) {
print(element);
});
return list;
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatelessWidget(),
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchapiCach(),
builder: (BuildContext context,
AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Container(
height: 10, width: 10, child: CircularProgressIndicator()));
} else {
print(snapshot.data);
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
title: Row(
children: [
Text(
"${snapshot.data![index]["key"]}",
style: TextStyle(fontSize: 25),
),
Expanded(
child: Align(
alignment: Alignment.topRight,
child: Text("${snapshot.data![index]["syncData"]}"),
)),
],
),
subtitle: Row(
children: [
Expanded(
child: Align(
alignment: Alignment.topRight,
child:
Text("${snapshot.data![index]["syncTime"]}")),
)
],
),
leading: CircleAvatar(),
);
});
}
;
});
}
}
pls, help if you can .i am trying to fetch some data from rest api .but on the getTreadingWallpapers() method it shows me full json data. but whenever I print snapshot.hasError on else condition.. it shows me false. it means the snapshot has not error..but why i am not getting the data in my future builder. no error showing , how can i solve this problem
class _FrontPageState extends State<FrontPage> {
Future<List<RecentPage>> recentPage;
RecentPage recentPagee;
bool isLoading = true;
List<RecentPage> wallpapers = new List();
Future<List<RecentPage>> getTrendingWallpapers() async {
// final url ="http://wallpaper.pkappstudio.info/api/api.php?action=get_recent";
String url = 'http://wallpaper.pkappstudio.info/api/api.php?action=get_recent';
final response =
await Http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
final Map = jsonDecode(response.body);
print("${response.body}");
isLoading = false;
final recentPaget = recentPageFromJson(response.body).asMap();
recentPaget.entries.forEach((element) => wallpapers.add(element.value));
return wallpapers;
} else {
throw Exception('Failed to load post');
}
}
#override
void initState() {
// TODO: implement initState
recentPage = getTrendingWallpapers();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: brandName(),elevation: 0.0,),
body: FutureBuilder(
future: recentPage,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none &&
snapshot.hasData == null) {
print('project snapshot data is: ${snapshot.data}');
return isLoading? Center(child: Container(child: Text("container"),)):Center(child: Container(child: Text("csdsdontainer"),));
}
if(snapshot.hasData){
return isLoading? Center(child: CircularProgressIndicator()):ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index){
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
physics: ClampingScrollPhysics(),
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: wallpapers.map((wallpapers){
return GridTile(child: GestureDetector(
onTap: (){
// Navigator.push(context, MaterialPageRoute(builder: (context)=>ImageView(
// imageUrl: wallpapers.src.potrait,
// )));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child:Image.network(snapshot.data.imageUrl, fit: BoxFit.cover,),
),
),
));
}).toList(),
),
);
},
);
} else return Container(child: Text("${snapshot.hasError}"),);
},
)
);
}
}
You can copy paste run full code below
Step 1: You do not need isLoading , you can directly use check ConnectionState
Step 2: You do not need to declare List<RecentPage> wallpapers, snapshot.data already keep this
code snippet
builder: (context, AsyncSnapshot<List<RecentPage>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
physics: ClampingScrollPhysics(),
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: snapshot.data.map((wallpapers) {
return GridTile(
child: GestureDetector(
onTap: () {
// Navigator.push(context, MaterialPageRoute(builder: (context)=>ImageView(
// imageUrl: wallpapers.src.potrait,
// )));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
wallpapers.imageUrl,
fit: BoxFit.cover,
working demo
full code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
List<RecentPage> recentPageFromJson(String str) =>
List<RecentPage>.from(json.decode(str).map((x) => RecentPage.fromJson(x)));
String recentPageToJson(List<RecentPage> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class RecentPage {
RecentPage({
this.no,
this.imageId,
this.imageUpload,
this.imageUrl,
this.type,
this.viewCount,
this.downloadCount,
this.featured,
this.tags,
this.categoryId,
this.categoryName,
});
int no;
String imageId;
String imageUpload;
String imageUrl;
Type type;
String viewCount;
String downloadCount;
Featured featured;
String tags;
String categoryId;
String categoryName;
factory RecentPage.fromJson(Map<String, dynamic> json) => RecentPage(
no: json["no"],
imageId: json["image_id"],
imageUpload: json["image_upload"],
imageUrl: json["image_url"],
type: typeValues.map[json["type"]],
viewCount: json["view_count"],
downloadCount: json["download_count"],
featured: featuredValues.map[json["featured"]],
tags: json["tags"],
categoryId: json["category_id"],
categoryName: json["category_name"],
);
Map<String, dynamic> toJson() => {
"no": no,
"image_id": imageId,
"image_upload": imageUpload,
"image_url": imageUrl,
"type": typeValues.reverse[type],
"view_count": viewCount,
"download_count": downloadCount,
"featured": featuredValues.reverse[featured],
"tags": tags,
"category_id": categoryId,
"category_name": categoryName,
};
}
enum Featured { YES, NO }
final featuredValues = EnumValues({"no": Featured.NO, "yes": Featured.YES});
enum Type { UPLOAD }
final typeValues = EnumValues({"upload": Type.UPLOAD});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
class FrontPage extends StatefulWidget {
#override
_FrontPageState createState() => _FrontPageState();
}
class _FrontPageState extends State<FrontPage> {
Future<List<RecentPage>> recentPage;
RecentPage recentPagee;
bool isLoading = true;
List<RecentPage> wallpapers = new List();
Future<List<RecentPage>> getTrendingWallpapers() async {
// final url ="http://wallpaper.pkappstudio.info/api/api.php?action=get_recent";
String url =
'http://wallpaper.pkappstudio.info/api/api.php?action=get_recent';
final response =
await http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
final Map = jsonDecode(response.body);
print("${response.body}");
isLoading = false;
final recentPaget = recentPageFromJson(response.body).asMap();
recentPaget.entries.forEach((element) => wallpapers.add(element.value));
return wallpapers;
} else {
throw Exception('Failed to load post');
}
}
#override
void initState() {
// TODO: implement initState
recentPage = getTrendingWallpapers();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text("brandName()"),
elevation: 0.0,
),
body: FutureBuilder(
future: recentPage,
builder: (context, AsyncSnapshot<List<RecentPage>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
physics: ClampingScrollPhysics(),
childAspectRatio: 0.6,
mainAxisSpacing: 6.0,
crossAxisSpacing: 6.0,
children: snapshot.data.map((wallpapers) {
return GridTile(
child: GestureDetector(
onTap: () {
// Navigator.push(context, MaterialPageRoute(builder: (context)=>ImageView(
// imageUrl: wallpapers.src.potrait,
// )));
},
child: Container(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Image.network(
wallpapers.imageUrl,
fit: BoxFit.cover,
),
),
),
));
}).toList(),
),
);
},
);
}
}
}));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FrontPage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
There is a good implementation of a FutureBuilder widget
Future<List<dynamic>> getTrendingWallpapers() async {
String url = 'http://wallpaper.pkappstudio.info/api/api.php?action=get_recent';
final response = await http.get(url, headers: {"Accept": "application/json"});
if (response.statusCode == 200) {
List<dynamic> wallpapers = List();
wallpapers.add(response.body);
return wallpapers;
} else {
throw Exception('Failed to load post');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: getTrendingWallpapers(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting || snapshot.connectionState == ConnectionState.none) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(
child: Text('Future error'),
);
}
if (snapshot.hasData) {
return Center(
child: Text('Do something with your snapshot.data : \n ${snapshot.data}'),
);
}
},
),
);
}
I've been trying to set a property based on a response from a FutureBuilder but can't seem to get it working. How can I set _activityLength after the future resolves without setting during build?
FutureBuilder<QuerySnapshot>(
future: _future,
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('Press button to start');
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
final documents = snapshot.data.documents;
_activityLength = documents.length;
return Expanded(
child: ListView.separated(
shrinkWrap: true,
separatorBuilder: (context, index) => Divider(
color: Colors.black,
height: 0,
),
itemCount: documents.length,
itemBuilder: (context, index) => _activityTile(
documents[index],
),
),
);
}
}
},
)
The FutureBuilde is in a Column widget in the body of the Scaffold and the value that I need to set is in the _itemsHeaderText Something like this:
body:
...
child: Column(
children: <Widget>[
Container(
width: double.infinity,
decoration: BoxDecoration(
border: Border(
bottom:
BorderSide(color: Colors.grey, width: 1.0),
),
),
child: Padding(
padding: const EdgeInsets.only(
left: 15.0,
right: 15.0,
top: 10.0,
bottom: 10.0),
child: _itemsHeaderText(),
),
),
_itemsBody(),
],
),
You can copy paste run full demo code below
You can use _future.then((value) in initState() and do job in addPostFrameCallback like setState
And after future resolves, you can get value of _future, you can do further processing if need
In demo code, I get value length and display on screen
You can see working demo, data length change from 0 to 9
code snippet
#override
void initState() {
super.initState();
_future = _getUsers();
_future.then((value) {
print("data length ${value.length}");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("other job");
setState(() {
_dataLength = value.length;
});
});
});
}
working demo
output
I/flutter (18414): data length 9
I/flutter (18414): other job
full code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: CategoryTab(title: 'Flutter Demo Home Page'),
);
}
}
class CategoryTab extends StatefulWidget {
CategoryTab({Key key, this.title}) : super(key: key);
final String title;
#override
_CategoryTabState createState() => _CategoryTabState();
}
class _CategoryTabState extends State<CategoryTab> {
Future<List<CategoryList>> _future;
int _dataLength = 0;
Future<List<CategoryList>> _getUsers() async {
var data = await http
.get("https://appiconmakers.com/demoMusicPlayer/API/getallcategories");
var jsonData = json.decode(data.body);
List<CategoryList> cat = [];
for (var u in jsonData) {
CategoryList categoryList = CategoryList(
u["category_id"],
u["category_name"],
u["parent_category_id"],
u["category_status"],
u["created_date"]);
cat.add(categoryList);
}
return cat;
}
#override
void initState() {
super.initState();
_future = _getUsers();
_future.then((value) {
print("data length ${value.length}");
WidgetsBinding.instance.addPostFrameCallback((_) {
print("other job");
setState(() {
_dataLength = value.length;
});
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Categories",
style: TextStyle(color: Colors.black),
),
backgroundColor: Colors.white,
),
body: Column(
children: [
Text("data length $_dataLength"),
Expanded(
child: Container(
child: FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Container(child: Center(child: Text("Loading...")));
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: CircleAvatar(),
title: Text(
"${snapshot.data[index].categoryName}",
// subtitle: Text(snapshot.data[index].categoryId
),
);
},
);
}
},
),
),
),
],
),
);
}
}
class CategoryList {
String categoryId;
String categoryName;
String parentCategoryId;
String categoryStatus;
String createdDate;
CategoryList(this.categoryId, this.categoryName, this.parentCategoryId,
this.categoryStatus, this.createdDate);
}
There are a few workarounds to your question.
You could hoist the futureBuilder up the widget tree, instead of setting state the state will be reset once ConnectionState.done.
You could place the future in a function that is called on init state, then the result of the future you set state on it.
I fetched some interest(data) through an API and show them using future builders as containers. I want to change the background color of the container when I clicked on it. Here is what I did and it's changing the background color of all the containers when I clicked on one.
I added an if condition to the color of the container to check whether it is clicked or not
color: isClicked? Colors.white : Color(0xFFFFEBE7),
and set the isClicked state to true when clicked.
bool isClicked = false;
FutureBuilder(
future: GetInterests.getInterests(),
builder: (context, snapshot) {
final datalist = snapshot.data;
if (snapshot.connectionState ==
ConnectionState.done) {
return Expanded(
child: SizedBox(
height: 35,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Wrap(
direction: Axis.vertical,
children: <Widget>[
GestureDetector(
onTap: (){
final inte_id = "${datalist[index]['_id']}";
log(inte_id);
setState(() {
isClicked = true;
});
},
child: new Container(
margin: EdgeInsets.only(right: 7),
height: 30,
width: MediaQuery.of(context)
.size
.width /
5.2,
decoration: BoxDecoration(
color: isClicked? Colors.white : Color(0xFFFFEBE7),
border: Border.all(
color: Color(0xFFE0E0E0)),
borderRadius:
BorderRadius.only(
topLeft:
Radius.circular(
50.0),
topRight:
Radius.circular(
50.0),
bottomRight:
Radius.circular(
50.0),
bottomLeft:
Radius.circular(
0.0))),
child: Center(
child: Text(
"${datalist[index]['iname']}",
style: TextStyle(
fontFamily: 'Montserrat',
color: Color(0xFFFF5E3A),
fontSize: 13),
),
),
),
),
],
);
},
itemCount: datalist.length,
),
),
);
}
return Padding(
padding: const EdgeInsets.only(left: 140.0),
child: Center(
child: CircularProgressIndicator(),
),
);
},
)
I was able to print the interest id in the console which belongs to the container I clicked on. but don't know how to change its color only
Instead of this you can use a variable to store selectedIndex and check if the currentIndex is selected or not and compare if currentIndex is selected or not and style the selected widget.
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatefulWidget {
_MyWidgetState createState()=>_MyWidgetState();
}
class _MyWidgetState extends State<MyWidget>{
List _selectedIndexs=[];
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 4,
itemBuilder: (ctx,i){
final _isSelected=_selectedIndexs.contains(i);
return GestureDetector(
onTap:(){
setState((){
if(_isSelected){
_selectedIndexs.remove(i);
}else{
_selectedIndexs.add(i);
}
});
},
child:Container(
color:_isSelected?Colors.red:null,
child:ListTile(title:Text("Khadga")),
),
);
}
);
}
}
modify your listview builder as i have done in above case.
While the accepted answer will work, a much more sophisticated architecture using ChangeNotifier and package provider will produce more loosely coupled, better code, in some folks opinion.
Combining ideas from the following
https://flutter.dev/docs/cookbook/networking/fetch-data
https://flutter.dev/docs/development/data-and-backend/state-mgmt/simple
I was focused on architecture and data flow. Not on widget layout to match the original question's screenshot.
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:provider/provider.dart';
// Model ---------------------------------------------------
class Interest with ChangeNotifier {
final String title;
bool _selected = false;
Interest({
#required this.title,
}) : assert(title != null);
factory Interest.fromMap(final Map<String, dynamic> map) {
return Interest(
title: map['title'],
);
}
bool get selected {
return this._selected;
}
void select() {
this._selected = true;
this.notifyListeners();
}
void toggleSelect() {
this._selected = !this._selected;
this.notifyListeners();
}
}
class Interests extends ChangeNotifier {
final List<Interest> _interests = <Interest>[];
Interests();
factory Interests.fromList(final List<Map<String, dynamic>> list) {
final Interests interests = Interests();
for (final Map<String, dynamic> map in list) {
interests.add(Interest.fromMap(map));
}
return interests;
}
int get length {
return this._interests.length;
}
Interest operator [](final int index) {
return this._interests[index];
}
UnmodifiableListView<Interest> get interests {
return UnmodifiableListView<Interest>(this._interests);
}
void add(final Interest interest) {
this._interests.add(interest);
this.notifyListeners();
}
void selectAll() {
for (final Interest interest in this._interests) {
interest.select();
}
}
}
// Services ------------------------------------------------
Future<Interests> fetchInterests() async {
// Some data source that has a list of objects with titles.
final response = await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
return Interests.fromList(json.decode(response.body).cast<Map<String, dynamic>>());
} else {
throw Exception('Failed to load post');
}
}
// User Interface ------------------------------------------
void main() {
runApp(InterestsApp());
}
class InterestsApp extends StatelessWidget {
#override
Widget build(final BuildContext context) {
return MaterialApp(
title: 'Interests App',
theme: ThemeData(primarySwatch: Colors.blue),
home: InterestsPage(),
);
}
}
class InterestsPage extends StatelessWidget {
#override
Widget build(final BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Interests')),
body: InterestsBody(),
);
}
}
class InterestsBody extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _InterestsBodyState();
}
}
class _InterestsBodyState extends State<InterestsBody> {
Future<Interests> _futureInterests;
#override
void initState() {
super.initState();
this._futureInterests = fetchInterests();
}
#override
Widget build(final BuildContext context) {
return FutureBuilder<Interests>(
future: this._futureInterests,
builder: (final BuildContext context, final AsyncSnapshot<Interests> snapshot) {
if (snapshot.hasData) {
return ChangeNotifierProvider.value(
value: snapshot.data,
child: InterestsList(),
);
} else if (snapshot.hasError) {
return Center(child: Text("${snapshot.error}"));
}
return Center(child: CircularProgressIndicator());
},
);
}
}
class InterestsList extends StatelessWidget {
#override
Widget build(final BuildContext context) {
return Consumer<Interests>(
builder: (final BuildContext context, final Interests interests, final Widget child) {
return Column(
children: <Widget>[
Center(
child: RaisedButton(
child: Text("Select All"),
onPressed: () {
interests.selectAll();
},
),
),
Expanded(
child: ListView.builder(
itemCount: interests.length,
itemBuilder: (final BuildContext context, final int index) {
return ChangeNotifierProvider<Interest>.value(
value: interests[index],
child: InterestTile(),
);
},
),
),
],
);
},
);
}
}
class InterestTile extends StatelessWidget {
#override
Widget build(final BuildContext context) {
return Consumer<Interest>(
builder: (final BuildContext context, final Interest interest, final Widget child) {
return ListTile(
title: Text(interest.title),
trailing: interest.selected ? Icon(Icons.check) : null,
onTap: () {
interest.toggleSelect();
},
);
},
);
}
}
you also can use flutter chip or ActionChip or ChoiceChip
class MyThreeOptions extends StatefulWidget {
#override
_MyThreeOptionsState createState() => _MyThreeOptionsState();
}
class _MyThreeOptionsState extends State<MyThreeOptions> {
int? _value = 1;
#override
Widget build(BuildContext context) {
return Wrap(
children: List<Widget>.generate(
3,
(int index) {
return ChoiceChip(
label: Text('Item $index'),
selected: _value == index,
onSelected: (bool selected) {
setState(() {
_value = selected ? index : null;
});
},
);
},
).toList(),
);
}
}