I'm trying to implement infinite scrolling in flutter using Getx and PageView.builder(). So far i've been able to get all the data from my firebase database to display the image, but i'm unable to implement the infinite pagination.
I want say 10 images to be displayed on first load (fetched from my firestore), and then as the user scrolls down to the 10th image, it should load the next 10 images from firestore.
Below is my code:
In my model i have a file name "image.dart" and it contains this:
import "package:cloud_firestore/cloud_firestore.dart";
class Images {
String username;
String uid;
String id;
List likes;
int commentCount;
int downloadCount;
String tag;
String description;
String imageUrl;
String profilePhoto;
bool verified;
Images({
required this.username,
required this.uid,
required this.id,
required this.likes,
required this.commentCount,
required this.downloadCount,
required this.tag,
required this.description,
required this.imageUrl,
required this.profilePhoto,
required this.verified,
});
Map<String, dynamic> toJson() => {
"username": username,
"uid": uid,
"id": id,
"likes": likes,
"commentCount": commentCount,
"downloadCount": downloadCount,
"tag": tag,
"description": description,
"imageUrl": imageUrl,
"profilePhoto": profilePhoto,
"verified": verified,
};
static Images fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
return Images(
username: snapshot['username'],
uid: snapshot['uid'],
id: snapshot['id'],
likes: snapshot['likes'],
commentCount: snapshot['commentCount'],
downloadCount: snapshot['downloadCount'],
tag: snapshot['tag'],
description: snapshot['description'],
imageUrl: snapshot['imageUrl'],
profilePhoto: snapshot['profilePhoto'],
verified: snapshot['verified']);
}
}
#
Then in my controller folder i have this file called image_controller.dart and it contains this:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ImageController extends GetxController {
var isDownloading = false.obs;
final Rx<List<Images>> _imageList = Rx<List<Images>>([]);
List<Images> get imageList => _imageList.value;
List<Map<String, dynamic>> list = [];
bool isMoreData = true;
DocumentSnapshot? lastDocument;
#override
void onInit() {
super.onInit();
_imageList.bindStream(
firestore.collection('images').snapshots().map((QuerySnapshot query) {
List<Images> retVal = [];
for (var element in query.docs) {
retVal.add(
Images.fromSnap(element),
);
}
return retVal;
}));
}
//................................code continues
Then in my view folder i have a file named image_screen.dart and it contains this:
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class ImageScreen extends StatelessWidget {
ImageScreen({Key? key}) : super(key: key);
final ImageController imageController = Get.put(ImageController());
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: Obx(() {
return PageView.builder(
itemCount: imageController.imageList.length,
controller: PageController(initialPage: 0, viewportFraction: 1),
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
final data = imageController.imageList[index];
return Stack(
children: [
ImagePlayerItem(
imageUrl: data.imageUrl,
),
Column(
children: [
const SizedBox(
height: 100,
),
// .................code continues...................
Related
this is RadioModel.dart
I am a beginner in flutter and I want to display my JSON file data on vx swipper.builder but i don't know whats going on here when i pass item count i face this error i know i am doing something wrong and i can't fix this
I am a beginner in flutter and I want to display my JSON file data on vx swipper.builder but i don't know whats going on here when i pass item count i face this error i know i am doing something wrong and i can't fix this
I am a beginner in flutter and I want to display my JSON file data on vx swipper.builder but i don't know whats going on here when i pass item count i face this error i know i am doing something wrong and i can't fix this
import 'dart:convert';
class MyRadioList {
static List<MyRadio>? radios;
// Get Item by ID
MyRadio getById(int id) =>
radios!.firstWhere((element) => element.id == id, orElse: null);
// Get Item by position
MyRadio getByPosition(int pos) => radios![pos];
}
class MyRadio {
final int id;
final int order;
final String name;
final String tagline;
final String color;
final String desc;
final String url;
final String category;
final String icon;
final String image;
final String lang;
MyRadio({
required this.id,
required this.order,
required this.name,
required this.tagline,
required this.color,
required this.desc,
required this.url,
required this.category,
required this.icon,
required this.image,
required this.lang,
});
factory MyRadio.fromMap(Map<String, dynamic> map) {
return MyRadio(
id: map['id'],
order: map['order'],
name: map['name'],
tagline: map['tagline'],
color: map['color'],
desc: map['desc'],
url: map['url'],
category: map['category'],
icon: map['icon'],
image: map['image'],
lang: map['lang'],
);
}
toMap() => {
"id": id,
"order": order,
"name": name,
"tagline": tagline,
"color": color,
"desc": desc,
"url": url,
"category": category,
"icon": icon,
"image": image,
"lang": lang,
};
}
// this is HomePage.dart
import 'dart:convert';
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_application_1/models/RadioModel.dart';
import 'package:flutter_application_1/utils/Ai_Utils.dart';
import 'package:velocity_x/velocity_x.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
//get daata from radio model
#override
void initstate() {
super.initState();
fetchradios();
}
fetchradios() async {
final radioJson = await rootBundle.loadString("assets/radio.json");
final decodedData = jsonDecode(radioJson);
MyRadioList.radios = List.from(decodedData)
.map<MyRadio>(((radio) => MyRadio.fromMap(radio)))
.toList();
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
drawer: Drawer(),
body: Stack(children: [
VxAnimatedBox()
.withGradient(LinearGradient(
colors: [AiColors.primaryColor1, AiColors.primaryColor2],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
))
.size(context.screenWidth, context.screenHeight)
.make(),
AppBar(
title: "AI Radio".text.xl4.bold.white.make().shimmer(
primaryColor: Vx.purple300, secondaryColor: Colors.white),
elevation: 0.0,
backgroundColor: Colors.transparent,
centerTitle: true,
).h(100.0).p16(),
VxSwiper.builder(
itemCount: MyRadioList.radios?.length, // error line
itemBuilder: (context, index) {
final rad = MyRadioList.radios![index];
return VxBox(child: ZStack([]))
.bgImage(DecorationImage(image: NetworkImage(rad.image)))
.make();
})
]),
);
}
}
itemCount must be a non-nullable int.
But your static List<MyRadio>? radios is a nullable List, so the length may be null if the List is never initialized
You can use the If-null operator ?? to initialize it to 0 or whatever default value you want to use if the length happens to be null
Change this line:
itemCount: MyRadioList.radios?.length, // error line
To this:
itemCount: MyRadioList.radios?.length ?? 0 // 0 or whatever default value
The line above essentially reads if MyRadioList.radios?.length is not null, then use it, otherwise set MyRadioList.radios?.length to 0.
Using ?? ensures that the length of your list will never be null
So i have my dart call to my api get method. Btw the way am just learning flutter and dart and trying out basic crud operations I would use to be doing in .net and c#
import 'dart:convert';
import 'package:theapp/models/Players.dart';
import 'package:http/http.dart';
class ApiService {
final String apiUrl = "https://apiurlhidden.com/api";
final String getAllPlayersEndPoint = "/GetAllPlayers/";
Future<List<Player>> getAllPlayers() async {
final getallPlayersUrl = Uri.parse(apiUrl + getAllPlayersEndPoint);
Response res = await get(getallPlayersUrl);
if (res.statusCode == 200) {
List<dynamic> body = jsonDecode(res.body);
List<Player> players =
body.map((dynamic item) => Player.fromJson(item)).toList();
return players;
} else {
throw "Failed to load cases list";
}
}
}
And I have my listview here but it complaining saying key and players do not exist
import 'package:flutter/material.dart';
import 'package:theapp/models/Players.dart';
class PlayerList extends StatelessWidget {
List<Player> players = [];
PlayerList({Key key, this.players}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: players == null ? 0 : players.length,
itemBuilder: (BuildContext context, int index) {
return Card(
child: InkWell(
onTap: () {},
child: ListTile(
leading: Icon(Icons.person),
title: Text(players[index].firstName),
subtitle: Text(players[index].surname.toString()),
),
));
});
}
}
My Model
class Player {
final int id;
final int type;
final String playerLevel;
final String firstName;
final String surname;
Player(this.id, this.type, this.playerLevel, this.firstName, this.surname);
factory Player.fromJson(Map<String, dynamic> json) {
return Player(
json['id'],
json['type'],
json['playerlevel'],
json['firstname'],
json['surname'],
);
}
#override
String toString() =>
'Players{id: $id, firstName: $firstName, lastName: $surname}';
}
Is there any reason why it should not recognize players and key in my list view page also how do I get the items to appear in the listview.
Picture only added to show the context in the items I mentioned above. Also coming from a .net background I would normally use an observable collection so it gets any changes in data in real-time am I using the correct approach for that.
Use required keyword to make parameters mandatory.
PlayerList({required Key key, required this.players}) : super(key: key);
Named parameters are optional unless they’re explicitly marked as required.
See Parameters for details.
Hello StackOverflow users,
I got stuck and I am not able to understand why I am receiving this error. So, let me explain me what I am doing,
This is my Home Page where my body of the Scaffold is a PageView, In the PageView the first page is TimeLine(currentUser: currentUser) where currentUser stores the details of the User.
home.dart
Scaffold buildAuthScreen() {
return Scaffold(
body: PageView(
children: [
Timeline(currentUser: currentUser),
ActivityFeed(),
Upload(currentUser: currentUser),
Search(),
Profile(profileId: currentUser?.id),
],
controller: pageController,
onPageChanged: onPageChanged,
physics: NeverScrollableScrollPhysics(),
),
);
}
This is TimeLine Page, in this Page I am just trying to print 'currentUser.id' and while doing that I am receiving the exception (The getter 'id' was called on null).
timeline.dart
class Timeline extends StatefulWidget {
final User currentUser;
Timeline({this.currentUser});
#override
_TimelineState createState() => _TimelineState();
}
class _TimelineState extends State<Timeline> {
#override
Widget build(context) {
print('Timeline : ${widget.currentUser.id}');
return Scaffold(
body: Text('Timeline'),
);
}
}
I was looking up the code to see why I am receiving the exception and then I want to Upload Page, the 3rd page of the PageView and tried to print 'currentUser.id' and interestingly it worked fine here although I am receiving an exception here too but after that the user.id is getting printed..
upload.dart
class Upload extends StatefulWidget {
final User currentUser;
Upload({this.currentUser});
#override
_UploadState createState() => _UploadState();
}
class _UploadState extends State<Upload> {
#override
Widget build(BuildContext context) {
print('Upload : ${widget.currentUser.id}');
return Scaffold(
body: Text('Upload'),
);
}
}
I am confused why this behaviour is happening. If anyone needs more information ping me but I provided the basic structure and I am facing this problem.
<--Update-->
Code where I set currentUser
void createUserInFirestore() async{
/* check if user exists in users.collection in database */
final GoogleSignInAccount user = googleSignIn.currentUser;
DocumentSnapshot doc = await usersRef.doc(user.id).get();
/* If the user doesn't exist then we will create account */
if(!doc.exists) {
final username = await Navigator.push(
context,
MaterialPageRoute(builder: (context) => CreateAccount())
);
/* Create new user from userName in users collection */
usersRef.doc(user.id).set({
"id": user.id,
"username": username,
"photoUrl": user.photoUrl,
"email": user.email,
"displayName": user.displayName,
"bio": "",
"timestamp": timestamp,
});
doc = await usersRef.doc(user.id).get();
}
currentUser = User.fromDocument(doc);
print('Create User in firestore : ${currentUser.id}');
}
}
User model class
class User {
final String id;
final String username;
final String email;
final String photoUrl;
final String displayName;
final String bio;
User({
this.id,
this.username,
this.email,
this.photoUrl,
this.displayName,
this.bio,
});
factory User.fromDocument(doc) {
return User(
id: doc.data()['id'],
username: doc.data()['username'],
email: doc.data()['email'],
photoUrl: doc.data()['photoUrl'],
displayName: doc.data()['displayName'],
bio: doc.data()['bio'],
);
}
}
[ Sorry for my bad English ]
In this project I'm viewing events lists in some pages from JSON API and in
CloudEvents page I'm viewing another list from Firebase Database, using Event model ...
Now when I run CloudEvents page I get null for itemsEvent[i].startDate
with this Error: A non-null String must be provided to a Text widget.
Open: Error Snapshot
Open: Firebase Database Snapshot
I used this Method for my model
This is my Event model
class Event {
String key;
String sectionID;
String sectionTitle;
String title;
String startDate;
String endDate;
String startDateAr;
String endDateAr;
String city;
String detail;
String location;
String more;
String link;
// for generalevent.json
String eventDate;
String eventDateAr;
Event(
{this.sectionID,
this.sectionTitle,
this.title,
this.startDate,
this.endDate,
this.startDateAr,
this.endDateAr,
this.city,
this.detail,
this.location,
this.more,
this.link,
this.eventDate,
this.eventDateAr});
factory Event.fromJson(Map<String, dynamic> json) {
return Event(
sectionID: json['section-id'],
sectionTitle: json['section-title'],
title: json['title'],
startDate: json['start-event-date'],
endDate: json['end-event-date'],
startDateAr: json['start-event-date-ar'],
endDateAr: json['end-event-date-ar'],
city: json['city'],
detail: json['detail'],
location: json['location'],
more: json['more'],
link: json['link'],
// for generalevent.json
eventDate: json['event-date'],
eventDateAr: json['event-date-ar'],
);
}
Event.fromSnapshot(DataSnapshot snapshot)
: key = snapshot.key,
title = snapshot.value['title'],
startDate = snapshot.value['startDate'];
toJson() {
return {
"title": title,
"startDate": startDate,
};
}
}
And this is my CloudEvents page
import 'package:events/UI/styleguide.dart';
import 'package:events/models/event.dart' as e;
import 'package:events/pages/account.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:intl/intl.dart' as intl;
final FirebaseAuth mAuth = FirebaseAuth.instance;
final db = FirebaseDatabase.instance.reference();
FirebaseUser mCurrentUser;
List<e.Event> itemsEvent = List();
e.Event itemEvent;
DatabaseReference dbEvent;
class CloudEvents extends StatefulWidget {
final GlobalKey<ScaffoldState> scaffoldKey;
const CloudEvents({Key key, #required this.scaffoldKey}) : super(key: key);
#override
_CloudEventsState createState() => _CloudEventsState();
}
class _CloudEventsState extends State<CloudEvents> {
ScrollController _hideButtonController;
var _isVisible;
#override
initState() {
super.initState();
...
itemEvent = e.Event();
final FirebaseDatabase database = FirebaseDatabase.instance;
dbEvent = database.reference().child('events');
dbEvent.onChildAdded.listen(_onEntryAddedEvent);
dbEvent.onChildChanged.listen(_onEntryChangedEvent);
...
}
_onEntryAddedEvent(Event event) {
setState(() {
itemsEvent.add(e.Event.fromSnapshot(event.snapshot));
});
}
_onEntryChangedEvent(Event event) {
var old = itemsEvent.singleWhere((entry) {
return entry.key == event.snapshot.key;
});
setState(() {
itemsEvent[e.Event.indexOf(old)] = e.Event.fromSnapshot(event.snapshot);
});
}
#override
Widget build(BuildContext context) {
return showEvents();
}
Widget showEvents(BuildContext context) {
return Container(
height: MediaQuery.of(context).size.height,
child: Stack(
children: <Widget>[
FirebaseAnimatedList(
query: dbEvent.child(mCurrentUser.uid),
itemBuilder: (_, DataSnapshot snapshot,
Animation<double> animation, int i) {
return new ListTile(
title: new Text(snapshot.value['title']), //snapshot works well
subtitle: new Text(itemsEvent[i].startDate), // this returns null
);
}),
...
],
),
);
}
...
}
I just realized the problem here, according to u/Cholojuanito's comment on reddit
I did his number 1 possible solution, and then I edited:
Text(itemsEvent[i].startDate) to
Text(e.Event.fromSnapshot(snapshot).startDate)
and it worked so well, thank you for everyone who commented on reddit.
I was building a DataTable from json call. Everything is going well but data is not showing.
//standing.dart
import '../modal/catelog_point_table_model.dart';
import '../services/category_point_table_services.dart';
import 'package:flutter/material.dart';
class DataTableWidget extends StatefulWidget {
#override
DataTableWidgetState createState() => DataTableWidgetState();
}
class DataTableWidgetState extends State<DataTableWidget> {
final List<String> cityColumns = [
'Team',
'M',
'W',
'NRR',
'Pts'
];
List<City> cities;
bool ascending;
#override
void initState() {
super.initState();
ascending = false;
}
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: width*1.5,
child: ListView(
children: <Widget>[
buildDataTable(),
],
),
),
);
}
Widget buildDataTable() => DataTable(
sortAscending: ascending,
columns: cityColumns
.map(
(String column) => DataColumn(
label: Text(column),
onSort: (int columnIndex, bool ascending) => onSortColumn(
columnIndex: columnIndex, ascending: ascending),
),
)
.toList(),
rows: cities.map((City city) => DataRow(
cells: [
DataCell(Text('${city.title}')),
DataCell(Text('${city.price}')),
DataCell(Text('${city.description}')),
DataCell(Text('${city.nrr}')),
DataCell(Text('${city.pts}')),
],
))
.toList(),
);
void onSortColumn({int columnIndex, bool ascending}) {
if (columnIndex == 0) {
setState(() {
if (ascending) {
cities.sort((a, b) => a.title.compareTo(b.title));
} else {
cities.sort((a, b) => b.title.compareTo(a.title));
}
this.ascending = ascending;
});
}
}
}
//catelog_point_table_model.dart
import 'dart:async' show Future;
import '../modal/catelog_point_table_model.dart';
import 'package:http/http.dart' as http;
import 'dart:async';
Future<List<City>> loadCatelog(String id) async {
String url = 'https://icc-point-table.nittodigital.now.sh/api/Catelogs/category/5ce1a425eda9891fa8b51430';
final response = await http.get(url);
print(response.body);
return cities(response.body);
}
//catelog_point_table_model.dart
import 'dart:convert';
class City {
final int imgcount;
final String id;
final String title;
final String price;
final String description;
final String nrr;
final String pts;
final List<String> gallery;
City({
this.imgcount,
this.id,
this.title,
this.price,
this.description,
this.nrr,
this.pts,
this.gallery
});
factory City.fromJson(Map<String, dynamic> parsedJson) {
var streetsFromJson = parsedJson['gallery'];
//print(streetsFromJson.runtimeType);
// List<String> streetsList = new List<String>.from(streetsFromJson);
List<String> galleryList = streetsFromJson.cast<String>();
return new City(
imgcount: parsedJson['img_v'],
id: parsedJson['_id'],
title: parsedJson['title'],
price: parsedJson['price'],
description: parsedJson['description'],
nrr: parsedJson['nrr'],
pts: parsedJson['pts'],
gallery: galleryList,
);
}
}
List<City> cities(str) {
final jsonData = json.decode(str);
return List<City>.from(jsonData.map((x) => City.fromJson(x)));
}
NoSuchMethodError: The method 'map' was called on null
This is what I am getting. Maybe I am not getting data because List is not static type.
it would be really nice if someone told me how to fetch the data correctly and make a bond with DataRow.
*sorry for my poor English.
You have to call your loadCatelog from inside your initState function. Since your call is async and initState does not allow async calls, you have to put the code in a seperate method:
#override
void initState() {
super.initState();
ascending = false;
_getData();
}
void _getData() async{
cities = await loadCatelog();
}
Also, you are asking for an id as a parameter for your function, but never use it. So either remove that parameter or pass it accordingly.
There would be an even more elegant way by using FutureBuilder if you only need to retreive the data from the API once, or StreamBuilder if you want to get live updates from said API.