how to implement refresh indicator in flutter - flutter

'''
I wanted to implement refresh indicator to reload data's from Api(Json). below code runs well but
pull down to refresh is not working. i tried to get the data's initially using initState and then view the data's using future builder. how can i achieve the refresh indicator to reload data's. what is missing from my code?
import 'package:flutter/material.dart';
import '../networkhelper/property.dart';
import '../widgets/recommended.dart';
import '../model/property.dart';
import '../shimmer/recommended.dart';
import '../widgets/home_top.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
late Future<List<PropertyModel>> _propertyData;
#override
void initState() {
_propertyData = PropertyApi.getProperty();
super.initState();
}
Future<void> _refreshData() async {
setState(() {
_propertyData = PropertyApi.getProperty();
});
await _propertyData;
}
#override
Widget build(BuildContext context) {
Size _screenSize = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.blue,
body: RefreshIndicator(
onRefresh: () => _refreshData(),
child: ListView(children: [
HomeTopView(),
Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: _screenSize.height * 0.02),
Padding(
padding: EdgeInsets.only(left: _screenSize.width * 0.04),
child: Text(
"Recommanded",
style: TextStyle(
fontSize: _screenSize.width * 0.055,
color: Colors.blue,
fontWeight: FontWeight.bold,
),
),
),
SizedBox(height: _screenSize.height * 0.01),
SizedBox(
height: _screenSize.height * 0.3,
child: FutureBuilder<List<PropertyModel>>(
future: _propertyData,
builder: (context, snapshot) {
if (snapshot.hasData) {
List<PropertyModel>? data = snapshot.data;
return ListView.builder(
shrinkWrap: true,
padding: EdgeInsets.only(
left: _screenSize.width * 0.015),
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemCount: data!.length,
itemBuilder: (context, index) {
return RecommendedItems(
id: data[index].id,
propertyName: data[index].name,
price: data[index].price,
imgUrl: data[index].img[2],
bedRoomQuantity: data[index].details.bedroom,
bathRoomQuantity: data[index].details.bathroom,
propertyArea: data[index].details.area,
address: data[index].address.city,
propertyType: data[index].details.propertytype,
);
},
);
} else if (snapshot.hasError) {
return Center(
child:
Text("Please Check Your Internet Connection"),
);
}
// By default show a loading spinner.
return ListView.builder(
itemCount: 4,
shrinkWrap: true,
padding: const EdgeInsets.only(left: 10),
scrollDirection: Axis.horizontal,
physics: const BouncingScrollPhysics(),
itemBuilder: (ctx, index) {
return RecommendedShimmer();
});
},
),
),
]),
),
// ),
]),
),
);
}
}
'''

Try changing your setState() method to this:
setState(() async {
_propertyData = await PropertyApi.getProperty();
});

Try this :
Future<void> _refreshData() async {
_propertyData = PropertyApi.getProperty();
setState(() {});
return;
}

This code works smoothly.
Future<void> _refreshData() async {
_propertyData = PropertyApi.getProperty();
await _propertyData;
setState(() {});
}

Related

Changing Text regarding to the TextField Simultaneously

I have a custom Text widget Named Dynamic_Game_Preview , and also a TextField.
I want the Dynamic_Game_Preview to be changed with the change of the TextField.
I used onChanged method for the TextField but all the letters are shown separately in the Dynamic_Game_Preview. How can I handle this changes to be applied in the same Dynamic_Game_Preview simultaneously with changing the TextField?
Here is my code:
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:pet_store/widgets/dynamic_game_preview.dart';
import 'main.dart';
class Dynamic_Game extends StatefulWidget {
const Dynamic_Game({Key? key}) : super(key: key);
#override
State<Dynamic_Game> createState() => _Dynamic_GameState();
}
class _Dynamic_GameState extends State<Dynamic_Game> {
TextEditingController nameController = TextEditingController();
List<String> names = [];
bool isLoading = false;
List<Dynamic_Game_Preview> dynamicList = [];
void initState() {
super.initState();
dynamicList = [];
names = [];
}
void addNames() {
if (names.length == 1) {
names = [];
}
names.add(nameController.text);
nameController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.indigo,
title: const Text('Dynamic Game'),
leading: GestureDetector(
child: const Icon(
Icons.arrow_back_ios,
color: Colors.white,
),
onTap: () {
// Navigator.pop(context);
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) => const HomePage(),
),
(route) => false,
);
},
),
),
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},
child: Center(
child: Column(
children: <Widget>[
SizedBox(height: 20),
Container(
margin: const EdgeInsets.symmetric(horizontal: 30),
child: TextField(
controller: nameController,
onChanged: (value) {
setState(() {
addNames();
});
},
decoration: const InputDecoration(
labelText: 'Enter a Pet Name',
),
),
),
SizedBox(height: 10),
Flexible(
fit: FlexFit.loose,
child: ListView.builder(
shrinkWrap: true,
itemCount: names.length,
itemBuilder: (_, index) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5.0, vertical: 3.0),
child: Dynamic_Game_Preview(nameController.text),
);
},
),
),
],
),
),
),
);
}
}
Problem
Your code clears the nameController:
void addNames() {
...
nameController.clear();
}
Then the code is trying to display nameController.text, which just got cleared:
Dynamic_Game_Preview(nameController.text)
Solution
Something along these lines should work:
itemBuilder: (_, index) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 5.0, vertical: 3.0),
child: Dynamic_Game_Preview(names[index]),
);
},
Last but not least
This probably is not needed:
onTap: () {
FocusScope.of(context).requestFocus(FocusNode());
},

Flutter Cubit fetching and displaying data

I'm trying to fetch data from Genshin API, code below is working, but only with delay (in GenshinCubit class), it looks weard, because I don't know how much time to set for delay. I think, there is a problem in code, cause it must not set the GenshinLoaded state before the loadedList is completed. Now, if I remove the delay, it just sets the GenshinLoaded when the list is still in work and not completed, await doesn't help. Because of that I get a white screen and need to hot reload for my list to display.
class Repository {
final String characters = 'https://api.genshin.dev/characters/';
Future<List<Character>> getCharactersList() async {
List<Character> charactersList = [];
List<String> links = [];
final response = await http.get(Uri.parse(characters));```
List<dynamic> json = jsonDecode(response.body);
json.forEach((element) {
links.add('$characters$element');
});
links.forEach((element) async {
final response2 = await http.get(Uri.parse(element));
dynamic json2 = jsonDecode(response2.body);
charactersList.add(Character.fromJson(json2));
});
return charactersList;
}
}
class GenshinCubit extends Cubit<GenshinState> {
final Repository repository;
GenshinCubit(this.repository) : super(GenshinInitial(),);
getCharacters() async {
try {
emit(GenshinLoading());
List<Character> list = await repository.getCharactersList();
await Future<void>.delayed(const Duration(milliseconds: 1000));
emit(GenshinLoaded(loadedList: list));
}catch (e) {
print(e);
emit(GenshinError());
}
}
}
class HomeScreen extends StatelessWidget {
final userRepository = Repository();
HomeScreen({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return BlocProvider<GenshinCubit>(
create: (context) => GenshinCubit(userRepository)..getCharacters(),
child: MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(body: Container(child: const CharactersScreen())),
),
);
}
}
class CharactersScreen extends StatefulWidget {
const CharactersScreen({
Key? key,
}) : super(key: key);
#override
State<CharactersScreen> createState() => _CharactersScreenState();
}
class _CharactersScreenState extends State<CharactersScreen> {
#override
Widget build(BuildContext context) {
return Column(
children: [
BlocBuilder<GenshinCubit, GenshinState>(
builder: (context, state) {
if (state is GenshinLoading) {
return Center(
child: CircularProgressIndicator(),
);
}
if (state is GenshinLoaded) {
return SafeArea(
top: false,
child: Column(
children: [
Container(
color: Colors.black,
height: MediaQuery.of(context).size.height,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: state.loadedList.length,
itemBuilder: ((context, index) {
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 50.0, horizontal: 50),
child: GestureDetector(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CharacterDetailsPage(
character: state.loadedList[index],
),
),
),
child: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Colors.blueAccent.withOpacity(0.3),
borderRadius: const BorderRadius.all(
Radius.circular(
30,
),
)),
child: Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
right: 30.0, bottom: 30),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
state.loadedList[index].name
.toString(),
style: TextStyle(
color: Colors.black,
fontSize: 50),
),
RatingBarIndicator(
itemPadding: EdgeInsets.zero,
rating: double.parse(
state.loadedList[index].rarity
.toString(),
),
itemCount: int.parse(
state.loadedList[index].rarity
.toString(),
),
itemBuilder: (context, index) =>
Icon(
Icons.star_rate_rounded,
color: Colors.amber,
))
],
),
),
),
),
),
);
})),
),
],
),
);
}
if (state is GenshinInitial) {
return Text('Start');
}
if (state is GenshinError) {
return Text('Error');
}
return Text('Meow');
}),
],
);
}
}
I found a solution!
I've got that problem because of forEach. How to wait for forEach to complete with asynchronous callbacks? - there is a solution.

Why i am not able to use setState Under GestureDetector

Why I am not able to use setState Under GestureDetector Using onTap:
After I use setState I got an error like: The function 'setState' isn't defined.
Try importing the library that defines 'setState', And VS Code editor show me
Error like: correcting the name to the name of an existing function, or defining a function named 'setState'.dart(undefined_function).
I try to fix different ways please tell me where is my problem
Thank you
Some Flutter Import Link ::::::::::
class ParsingMap extends StatefulWidget {
const ParsingMap({Key? key}) : super(key: key);
#override
_ParsingMapState createState() => _ParsingMapState();
}
class _ParsingMapState extends State<ParsingMap> {
Future<ApiList>? data;
#override
void initState() {
super.initState();
Network network = Network("https://fakestoreapi.com/products");
data = network.loadPosts();
// print(data);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
elevation: 0,
leading: Icon(Icons.arrow_left, color: Colors.black),
actions: [
Icon(Icons.search, color: Colors.black),
SizedBox(width: 10),
Icon(Icons.home_filled, color: Colors.black),
SizedBox(width: 8)
],
),
body: Center(
child: Container(
child: FutureBuilder(
future: data,
builder: (context, AsyncSnapshot<ApiList> snapshot) {
List<Api> allPosts;
if (snapshot.hasData) {
allPosts = snapshot.data!.apis!;
return createListView(allPosts, context);
}
return CircularProgressIndicator();
},
),
),
),
);
}
}
class Network {
final String url;
Network(this.url);
Future<ApiList> loadPosts() async {
final response = await get(Uri.parse(url));
if (response.statusCode == 200) {
// print(response.body);
return ApiList.fromJson(json.decode(response.body));
} else {
throw Exception("Faild To get posts");
}
}
}
Widget createListView(List<Api> data, BuildContext context) {
return ListView(
children: [
Container(
height: 300,
margin: EdgeInsets.symmetric(vertical: 16),
child: ListView.builder(
itemCount: data.length,
scrollDirection: Axis.horizontal,
physics: BouncingScrollPhysics(),
padding: EdgeInsets.symmetric(horizontal: 16),
itemBuilder: (context, index) {
int selectedIndex = 0;
return GestureDetector(
onTap: () {
setState(() {
selectedIndex = index;
});
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"${data[index].category}",
style: TextStyle(
fontWeight: FontWeight.bold,
color: selectedIndex == index
? Colors.black
: Colors.black38),
),
Container(
margin: EdgeInsets.only(
top: 5,
),
height: 2,
width: 30,
color: selectedIndex == index
? Colors.black
: Colors.transparent,
)
],
),
),
);
},
),
),
],
);
}
Put top-level createListView function in _ParsingMapState class.
class _ParsingMapState extends State<ParsingMap> {
// ...
Widget createListView(...) {}
}

Flutter GridView in TabBar causing lag because of my code

There is a GridView in my TabBar which has two tabs and this tab is the 2nd one which is causing some UI lag. When I fetched some image in the GridView, I didn't experience any lag so I think I've done something wrong in my code which involves Futures which is loading videos from the internal storage directory. Also I have read about HandlerThread that it can help with the issue but I don't know how to implement it.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:thumbnails/thumbnails.dart';
import 'package:wastatusapp/utils/video_play.dart';
final Directory _videoDir =
Directory('/storage/emulated/0/WhatsApp/Media/.Statuses');
class VideoScreen extends StatefulWidget {
const VideoScreen({Key key}) : super(key: key);
#override
VideoScreenState createState() => VideoScreenState();
}
class VideoScreenState extends State<VideoScreen> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
if (!Directory('${_videoDir.path}').existsSync()) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'Install WhatsApp\n',
style: TextStyle(fontSize: 18.0),
),
const Text(
"Your Friend's Status Will Be Available Here",
style: TextStyle(fontSize: 18.0),
),
],
);
} else {
return VideoGrid(directory: _videoDir);
}
}
}
class VideoGrid extends StatefulWidget {
final Directory directory;
const VideoGrid({Key key, this.directory}) : super(key: key);
#override
_VideoGridState createState() => _VideoGridState();
}
class _VideoGridState extends State<VideoGrid> {
Future<String> _getImage(videoPathUrl) async {
//await Future.delayed(Duration(milliseconds: 500));
final thumb = await Thumbnails.getThumbnail(
videoFile: videoPathUrl,
imageType:
ThumbFormat.PNG, //this image will store in created folderpath
quality: 10);
return thumb;
}
#override
Widget build(BuildContext context) {
final videoList = widget.directory
.listSync()
.map((item) => item.path)
.where((item) => item.endsWith('.mp4'))
.toList(growable: false);
if (videoList != null) {
if (videoList.length > 0) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 8.0),
child: GridView.builder(
itemCount: videoList.length,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.7,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8,
),
itemBuilder: (context, index) {
return InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PlayStatus(
videoFile: videoList[index],
),
),
),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(12)),
child: Container(
child: FutureBuilder(
future: _getImage(videoList[index]),
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
if (snapshot.hasData) {
return Hero(
tag: videoList[index],
child: Image.file(
File(snapshot.data),
fit: BoxFit.cover,
),
);
} else {
return Center(
child: Column(
children: [
Text(
"Open WhatsApp with your internet on and then try again."),
Text(
"Make sure you have good internet connection!")
],
),
);
}
} else {
return Container(
child:
Image.asset('assets/images/video_loader.gif'),
);
}
}),
//new cod
),
),
);
},
),
);
} else {
return const Center(
child: Text(
'Sorry, No Videos Found.',
style: TextStyle(fontSize: 18.0),
),
);
}
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
}
}

I want to view the PDF file when the user taps on the cover

I want to view the PDF file when the user taps on the cover. I am new to Flutter.
Can you guys find out whats wrong in my code? When I tap on the book, it does nothing.
I think the problem is in the function for the PDF Viewer.
I am using advance_pdf_viewer 1.1.6.
class Books extends StatefulWidget {
#override
_BooksState createState() => _BooksState();
}
class _BooksState extends State<Books> {
bool _isLoading = true;
PDFDocument document;
var url;
#override
void initState() {
super.initState();
loadDocument();
}
loadDocument() async {
document = await PDFDocument.fromURL(url);
setState(() => _isLoading = false);
}
changePDF(value) async {
setState(() => _isLoading = true);
if (value == 1) {
document = await PDFDocument.fromURL(url);
} else {
print('nothing');
}
setState(() => _isLoading = false);
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: Firestore.instance.collection('books').snapshots(),
builder: (
context,
snapshot,
) {
if (snapshot.data == null)
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.red,
valueColor: new AlwaysStoppedAnimation<Color>(Colors.teal),
),
);
return GridView.builder(
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3, childAspectRatio: 0.7),
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.all(8.0),
child: GridTile(
child: InkWell(
onTap: () async {
PDFDocument.fromURL(snapshot.data.documents[index]['url']);
_isLoading
? Center(child: CircularProgressIndicator())
: PDFViewer(document: document);
},
child: Container(
height: 200,
width: 110,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.red[500].withOpacity(0.6),
spreadRadius: 0.5,
blurRadius: 1,
offset: Offset(2, 0),
),
],
color: Colors.white,
borderRadius: BorderRadius.circular(3),
border: Border.all(
style: BorderStyle.solid,
color: Colors.red[500],
width: 0.3)),
child: Column(children: <Widget>[
Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
child: Image.network(
snapshot.data.documents[index]['image'],
width: 100,
),
),
),
SizedBox(height: 5),
Text(
snapshot.data.documents[index]['name'],
)
]),
),
),
),
),
);
});
}
}
PDFViewer returns a Widget. If you want to view the pdf file when tapping on the InkWell you need to make a widget that displays the widget that PDFViewer returns, e.g.,
class PDFScreen extends StatelessWidget {
PDFDocument document;
PDFScreen({#required this.document});
#override
Widget build(BuildContext context) {
return Scaffold(
child: PDFViewer(document: document)
);
}
}
And change the onTap() of the InkWell to:
onTap: () async {
PDFDocument.fromURL(snapshot.data.documents[index]['url']);
_isLoading
? Center(child: CircularProgressIndicator())
: Navigator.push(context, MaterialPageRoute(builder: (context) => PDFScreen(document: document)));
},