FutureBuilder operated without initState in flutter - flutter

I work with FutureBuilder to view a set of data through GridView by FutureBuilder but there are one problem the data is view without put method in initState().I don't know why it works without putting it in initState().
full code:
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
}
bool showicon = false;
var apiURL;
Future getdataCat() async {
setState(() {
showicon = true;
});
apiURL = '***********************';
var response = await http.post(Uri.parse(apiURL));
var responsebody = jsonDecode(response.body);
if (responsebody.length > 0) {
return responsebody;
} else {
showicon = false;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Flexible(
child: FutureBuilder(
future: getdataCat(),
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
// still waiting for data to come
return showicon
? Center(
child: CircularProgressIndicator(
color: Colors.black,
))
: SizedBox(
height: 10,
child: Center(
child: Image.asset(
'assets/data.png',
)));
} else if (snapshot.hasData &&
snapshot.data.isEmpty &&
snapshot.data <= 0) {
return SizedBox(
height: 10,
child: Center(
child: Image.asset(
'assets/data.png',
)));
} else {
return GridView.builder(
physics: ScrollPhysics(),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, childAspectRatio: 3.4),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
child: Card(
child: Column(
children: <Widget>[
Flexible(
child: GestureDetector(
child: Column(children: <Widget>[
Center(
child: Text(
"${snapshot.data[index]['name']}"))
]),
)),
],
),
),
);
},
);
}
},
),
)
],
),
),
);
}
}
As you can see I not make any thing in initState() but it's still working.
I need to stop it if I don't put it in initState().Because I need to run a different function before it.

I prefer this way. You can check Randal L. Schwartz video
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late final Future<List<int>?> myFuture;
#override
void initState() {
super.initState();
myFuture = getCatData();
}
Future<List<int>?> getCatData() async {
await Future.delayed(Duration(seconds: 2));
//your operations
return [1, 2, 5];
// return [];
}
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () {
setState(() {});
}),
body: Center(
child: Column(
children: <Widget>[
Flexible(
child: FutureBuilder<List<int>?>(
future: myFuture,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const CircularProgressIndicator();
}
if (snapshot.hasError) {
return Text("Error ${snapshot.error}");
}
if (!snapshot.hasData) {
return Text("no Data found");
}
if (snapshot.data!.isEmpty) {
return Text("Empty found");
}
if (snapshot.hasData) {
return GridView.builder(
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3.4,
),
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
child: Text(snapshot.data[index].toString()));
},
);
}
return Text("NA");
},
),
)
],
),
),
);
}
}

Point of FutureBuilder is to run a function that will return with the data you want to use to build your widgets.
You already call your method in the FutureBuilder:
FutureBuilder(
future: getdataCat(),
builder: (context, AsyncSnapshot snapshot) {...}
)

Related

Flutter: BottomNavigationBar malfunctions when referring to the same page/widget

I have a BottomNavigationBar and realized that when I was changing the index I was displaying pretty much the exact same page/widget except for a 2 parameters. So I decided to consolidate the widgets into one that take in the parameters, but the issue is that now that I did that it doesn't work. I assume it has something to do with the page already being initialized and having a state? Here is what my widget with the BottomNavigationBar looks like:
class SpeedPage extends StatefulWidget {
const SpeedPage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _SpeedPageState();
}
}
class _SpeedPageState extends State<SpeedPage> {
int _currentIndex = 0;
static const List<Widget> _widgetOptions = <Widget>[
WorkoutListPage(categoryIndex: 0, subCategories: Utils.srsDropdown),
WorkoutListPage(categoryIndex: 1, subCategories: Utils.ddsDropdown),
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [_widgetOptions.elementAt(_currentIndex)],
)),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: const [
BottomNavigationBarItem(
icon: Icon(Icons.looks_one_outlined),
label: 'Single rope',
backgroundColor: Color.fromRGBO(204, 16, 138, 1)),
BottomNavigationBarItem(
icon: Icon(Icons.looks_two_outlined),
label: 'Double dutch',
backgroundColor: Color.fromRGBO(204, 16, 138, 1)),
],
onTap: _onItemTapped,
),
);
}
void _onItemTapped(int index) {
setState(() {
_currentIndex = index;
});
}
}
and here is what my WorkoutListPage widget looks like:
class WorkoutListPage extends StatefulWidget {
final int categoryIndex;
final List<String> subCategories;
const WorkoutListPage(
{Key? key, required this.categoryIndex, required this.subCategories})
: super(key: key);
#override
State<StatefulWidget> createState() {
return _WorkoutListPageState();
}
}
class _WorkoutListPageState extends State<WorkoutListPage> {
bool isLoading = true;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(widget.categoryIndex, widget.subCategories)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
and this doesn't work – it lags between tabs or the page simply doesn't change. Ironically, if in my SpeedPage I change my _widgetOptions to be the following:
static const List<Widget> _widgetOptions = <Widget>[
SpeedSRPage(),
SpeedDDPage()
];
where my SpeedSRPage() and SpeedDDPage() are:
class SpeedSRPage extends StatefulWidget {
const SpeedSRPage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _SpeedSRPageState();
}
}
class _SpeedSRPageState extends State<SpeedSRPage> {
var isLoading = true;
#override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(0, Utils.srsDropdown)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
and
class SpeedDDPage extends StatefulWidget {
const SpeedDDPage({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() {
return _SpeedDDPageState();
}
}
class _SpeedDDPageState extends State<SpeedDDPage> {
var isLoading = true;
#override
Widget build(BuildContext context) =>
FutureBuilder<List<Map<String, dynamic>>>(
future: MyCard.getData(1, Utils.ddsDropdown)!
.whenComplete(() => setState(() {
isLoading = false;
})),
builder: ((context, snapshot) {
if (snapshot.hasData && snapshot.data!.isNotEmpty) {
return FutureBuilder<List<MyCard>>(
future: MyCard.readData(snapshot.data),
builder: (context, cards) {
if (cards.hasData) {
final card = cards.data!;
return Expanded(
child: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: card.length,
itemBuilder: (context, index) {
return MyCard.buildCard(card[index], context);
},
),
);
} else {
return const Text("No data");
}
});
} else {
return isLoading
? Column(
children: const [CircularProgressIndicator()],
)
: const Text("You do not have any workouts yet");
}
}),
);
}
respectively, it works. I also know that it isn't a problem with the WorkoutListPage because if I change my _widgetOptions to something like:
static const List<Widget> _widgetOptions = <Widget>[
WorkoutListPage(categoryIndex: 0, subCategories: Utils.srsDropdown),
SpeedDDPage(),
];
it also works. So the issue seems to be that I am using the same widget (WorkoutListPage) twice in one BottomNavigationBar. I suspect it has something to do with the state initiation; if I add this line to the workoutListPageState():
void initState() {
print("Initiated state");
super.initState();
}
"Initiated state" only prints once if I switch tabs and the items in my _widgetOptions are both a WorkoutListPage. But if I switch my _widgetOptions to have different widgets "Initiated state" prints out every time I change tabs.

PageView.builder move to the next page if based on a value from future (api)

I have a FutureBuilder and inside is a PageView.builder. The future is calling an api and a list of flags is being fetched from the server. The flags are based on '0' & '1' like this ['1','1','0','0']. What I want to do is to skip the pages from start that have flag '1'. In this case, page first should be the first '0' at index 2. However, all pages should be built in case user want to see the previous pages as well.
Here is my code:
import 'package:flutter/material.dart';
class ScreenForBuilder extends StatefulWidget {
const ScreenForBuilder({Key? key}) : super(key: key);
#override
State<ScreenForBuilder> createState() => _ScreenForBuilderState();
}
class _ScreenForBuilderState extends State<ScreenForBuilder> {
List isCompleted = [];
apiCallFunction() async {
isCompleted = ['1','1','0','0'];
return isCompleted;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: FutureBuilder(
future: apiCallFunction(),
builder: (context, snapshot){
return PageView.builder(
itemCount: 4,
itemBuilder: (context, index){
return Center(
child: Text('${index+1}', style: const TextStyle(fontSize: 50),),
);
}
);
}
),
),
);
}
}
you can set the initialPage in the PageController
class ScreenForBuilder extends StatefulWidget {
const ScreenForBuilder({Key? key}) : super(key: key);
#override
State<ScreenForBuilder> createState() => _ScreenForBuilderState();
}
class _ScreenForBuilderState extends State<ScreenForBuilder> {
List isCompleted = [];
Future<List<String>> apiCallFunction() async {
List<String> isCompleted = ['1','1','0','0'];
return isCompleted;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: FutureBuilder<List<String>>(
future: apiCallFunction(),
builder: (context, snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError || !snapshot.hasData) {
return const Center(
child: Text('something went wrong'),
);
}
final initialPage = snapshot.data!.indexWhere(
(element) => element == '0',
);
return PageView.builder(
controller: PageController(
initialPage: initialPage == -1 ? 0 : initialPage,
),
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return Center(
child: Text(
'${index + 1}',
style: const TextStyle(fontSize: 50),
),
);
},
);
},
),
),
);
}
}
The code #Hydra provided worked great for me but here is an alternative method. I set the initial page with indexOf a flag. Here's my code that also worked.
import 'package:flutter/material.dart';
class ScreenForBuilder extends StatefulWidget {
const ScreenForBuilder({Key? key}) : super(key: key);
#override
State<ScreenForBuilder> createState() => _ScreenForBuilderState();
}
class _ScreenForBuilderState extends State<ScreenForBuilder> {
List isCompleted = [];
apiCallFunction() async {
isCompleted = ['1','1','0','0'];
return isCompleted;
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: FutureBuilder(
future: apiCallFunction(),
builder: (context, snapshot){
if(snapshot.hasData) {
return PageView.builder(
controller: PageController(initialPage: isCompleted.indexOf('0')),
itemCount: isCompleted.length,
itemBuilder: (context, index){
return Center(
child: Text('${index}', style: const TextStyle(fontSize: 50),),
);
}
);
} else
return CircularProgressIndicator();
}
),
),
);
}
}

How to make flutter_vlc_player work with data from an api

I'm working with an api that returns some tv livestreams . But i can't really figure how to work around with the flutter_vlc_player which is specifically what i want to use. its documentation
I've tried but i'm getting the error _videoPlayerController has not been initialized
Here is my code
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter_vlc_player/flutter_vlc_player.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
Future<List<dynamic>> fetchMedia() async {
final result = await http
.get(Uri.parse('https://iptv-org.github.io/api/streams.json'));
return json.decode(result.body);
}
String _name(dynamic media) {
return media['channel'];
}
String _location(dynamic media) {
return media['url'];
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: FutureBuilder<List<dynamic>>(
future: fetchMedia(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
return ListView.builder(
padding: EdgeInsets.all(8),
itemCount: 10,
itemBuilder: (BuildContext context, int index){
late VlcPlayerController _videoPlayerController;
#override
void dispose() async {
super.dispose();
await _videoPlayerController.stopRendererScanning();
await _videoPlayerController.dispose();
}
String url = _location(snapshot.data[index]);
#override
void initState() {
super.initState();
_videoPlayerController = VlcPlayerController.network(
url,
autoPlay: false,
options: VlcPlayerOptions(),
);
}
return
Card(
child: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.tv),
title: Text(_name(snapshot.data[index])),
subtitle:SizedBox(
child: VlcPlayer(
controller: _videoPlayerController,
aspectRatio: 16/ 9,
placeholder: Center(child: CircularProgressIndicator()),
),),)],
),):});
}else {
return Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}
What i want to achieve is that for each media url of a particular index to be passed into the VlcPlayerController.network()
Can somebody help please !!
Scaffold(
body: FutureBuilder<List<dynamic>>(
future: fetchMedia(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: 10,
itemBuilder: (BuildContext context, int index) {
String url = _location(snapshot.data[index]);
VlcPlayerController videoPlayerController =
VlcPlayerController.network(
url,
autoPlay: false,
options: VlcPlayerOptions(),
);
#override
void dispose() async {
super.dispose();
await videoPlayerController.stopRendererScanning();
await videoPlayerController.dispose();
}
#override
void initState() {
super.initState();
videoPlayerController = VlcPlayerController.network(
url,
autoPlay: false,
options: VlcPlayerOptions(),
);
}
return Card(
child: Column(
children: <Widget>[
ListTile(
leading: Icon(Icons.tv),
title: Text(_name(snapshot.data[index])),
subtitle: SizedBox(
child: VlcPlayer(
controller: videoPlayerController,
aspectRatio: 16 / 9,
placeholder:
Center(child: CircularProgressIndicator()),
),
),
)
],
),
);
});
} else {
return Center(child: CircularProgressIndicator());
}
},
),
);
Here is the updated code for flutter_vlc_player Please do make sure the android minimum SDK to 20 otherwise the project will not run.

How to play a List of video carousel?

I want to create a List of video carousel, something similar to a social media platform.
I tried making video carousel using flutter_swiper and video_player. and created a list using inview_notifier_list 's autoplay example, But unable to get the desired output.
class VideoList extends StatefulWidget {
#override
_VideoListState createState() => _VideoListState();
}
class _VideoListState extends State<VideoList> {
List<String> videoList = [
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
'https://flutter.github.io/assets-for-api-docs/assets/videos/butterfly.mp4',
];
String videoToPlay;
#override
void initState() {
super.initState();
videoToPlay = videoList[0];
}
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InViewNotifierList(
scrollDirection: Axis.vertical,
initialInViewIds: ['0'],
isInViewPortCondition:
(double deltaTop, double deltaBottom, double viewPortDimension) {
return deltaTop < (0.5 * viewPortDimension) &&
deltaBottom > (0.5 * viewPortDimension);
},
itemCount: 5,
builder: (context, index) => Container(
width: double.infinity,
height: 300.0,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 50.0),
child: SizedBox(
height: 300,
width: double.infinity,
child: Swiper(
onIndexChanged: (i) {
setState(() {
videoToPlay = videoList[i];
});
},
itemCount: videoList.length,
itemBuilder: (context, index) => LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
final InViewState inViewState =
InViewNotifierList.of(context);
inViewState.addContext(context: context, id: '$index');
return AnimatedBuilder(
animation: inViewState,
builder: (BuildContext context, Widget child) {
return VideoWidget(
play: inViewState.inView('$index'),
url: videoToPlay);
},
);
},
),
),
),
),
),
Align(
alignment: Alignment.center,
child: Container(
height: 1.0,
color: Colors.redAccent,
),
)
],
);
}
}
and below is my video class, where the video player is initialized
class VideoWidget extends StatefulWidget {
final String url;
final bool play;
const VideoWidget({Key key, #required this.url, #required this.play})
: super(key: key);
#override
_VideoWidgetState createState() => _VideoWidgetState();
}
class _VideoWidgetState extends State<VideoWidget> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
#override
void initState() {
super.initState();
_controller = VideoPlayerController.network(widget.url);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
if (widget.play) {
_controller.play();
_controller.setLooping(true);
}
}
#override
void didUpdateWidget(VideoWidget oldWidget) {
if (oldWidget.play != widget.play) {
if (widget.play) {
_controller.play();
_controller.setLooping(true);
} else {
_controller.pause();
}
}
super.didUpdateWidget(oldWidget);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return VideoPlayer(_controller);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
Could someone please help out, What should be the correct approach?
So here I am sharing my solution How did i manged to create a List of video cousrsel.
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InViewNotifierList(
scrollDirection: Axis.vertical,
initialInViewIds: ['0'],
isInViewPortCondition:
(double deltaTop, double deltaBottom, double viewPortDimension) {
return deltaTop < (0.5 * viewPortDimension) &&
deltaBottom > (0.5 * viewPortDimension);
},
itemCount: 5,
builder: (context, index) => Container(
width: double.infinity,
height: 300.0,
alignment: Alignment.center,
margin: EdgeInsets.symmetric(vertical: 50.0),
child: LayoutBuilder(
builder: (BuildContext context, BoxConstraints constraints) {
print('layout called');
final InViewState inViewState = InViewNotifierList.of(context);
inViewState.addContext(context: context, id: '$index');
return PageView.builder(
itemCount: videoList.length,
itemBuilder: (context, indexPage) => AnimatedBuilder(
animation: inViewState,
builder: (BuildContext context, Widget child) {
return VideoWidget(
play: inViewState.inView('$index'),
url: videoList[indexPage]);
},
),
);
},
),
),
),
Align(
alignment: Alignment.center,
child: Container(
height: 1.0,
color: Colors.redAccent,
),
)
],
);
}
}
where my video List is the list of URL of videos.

my snapshot doesn't have the data in futurebuilder

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}'),
);
}
},
),
);
}