How to display users based on category? I have never done this. What is the logic behind this to implement
Here is my AllUsersProvider class:
class AllUsersProvider extends ChangeNotifier {
bool isLoading = false;
List<UsersData>? userData = [];
Future<void> getAllUsers(BuildContext context) async {
isLoading = true;
notifyListeners();
try {
bool isConnected = await NetworkHelper.checkInternet();
if (!isConnected) {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Kindly Connect to internet")));
} else {
final response = await ApiService.getUsers();
isLoading = false;
notifyListeners();
if (response.statusCode == 200) {
final jsonResponse = json.decode(response.body);
if (jsonResponse.containsKey("success")) {
if (jsonResponse["success"]) {
UsersModel usersModel = UsersModel.fromJson(jsonResponse);
userData = usersModel.data;
notifyListeners();
}
}
} else {
ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("Something went wrong")));
}
}
} catch (error) {
print(error);
isLoading = false;
notifyListeners();
}
}
}
And here I want to display users based on category
class UsersCategory extends StatefulWidget {
final int categoryId;
final List<HomeCategory>? categories;
const UsersCategory({Key? key, required this.categoryId, required this.categories}) : super(key: key);
#override
State<UsersCategory> createState() => _UsersCategoryState();
}
class _UsersCategoryState extends State<UsersCategory> {
late int _categoryId;
#override
void initState() {
super.initState();
_categoryId = widget.categoryId;
Provider.of<AllUsersProvider>(context, listen: false).getAllUsers(context);
}
void _updateCategoryId(int newCategoryId) {
setState(() {
_categoryId = newCategoryId;
});
}
#override
Widget build(BuildContext context) {
print(widget.categoryId);
return Scaffold(
appBar: AppBar(
title: const Text("Users Category"),
),
body: Column(
children: [
const Text("Category"),
const SizedBox(height: 15),
SizedBox(
width: double.infinity,
height: 80,
child: ListView.builder(
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: widget.categories?.length ?? 0,
itemBuilder: (context, index) => GestureDetector(
onTap: () {
_updateCategoryId(widget.categories?[index].id ?? 0);
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Column(
children: [
Container(
height: 50,
width: 50,
decoration: BoxDecoration(
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black.withOpacity(0.5),
blurRadius: 10,
offset: const Offset(0.0, 5),
)
],
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
child: Image.network(
widget.categories?[index].photo.toString() ?? "",
fit: BoxFit.contain,
),
),
const SizedBox(height: 5),
Text(widget.categories?[index].enName.toString() ?? ""),
],
),
),
),
),
),
const SizedBox(height: 15),
ShowUsersBasedOnCategory(categoryId: _categoryId)
],
),
);
}
}
class ShowUsersBasedOnCategory extends StatefulWidget {
final int categoryId;
const ShowUsersBasedOnCategory({Key? key, required this.categoryId}) : super(key: key);
#override
State<ShowUsersBasedOnCategory> createState() => _ShowUsersBasedOnCategoryState();
}
class _ShowUsersBasedOnCategoryState extends State<ShowUsersBasedOnCategory> {
#override
Widget build(BuildContext context) {
return Expanded(
child: Consumer<AllUsersProvider>(builder: (context, provider, _) {
List<UsersData>? users = provider.userData?.where((user) => user.categoryId == widget.categoryId).toList();
if (provider.isLoading) {
return const Center(
child: CircularProgressIndicator(),
);
} else if (users == null || users.isEmpty) {
return const Center(
child: Text("No users found for this category"),
);
} else {
return GridView.builder(
itemCount: users.length,
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 7 / 5,
crossAxisCount: 2,
mainAxisSpacing: 15,
),
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Container(
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10),
),
child: Center(child: Text(users[index].firstName.toString())),
),
),
);
}
}),
);
}
}
When i click on category i also face this error
setState() or markNeedsBuild() called during build.
This _InheritedProviderScope<AllUsersProvider?> widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was: _InheritedProviderScope<AllUsersProvider?>
value: Instance of 'AllUsersProvider'
listening to value
The widget which was currently being built when the offending call was made was: Builder
When the exception was thrown, this was the stack:
#0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:4634:9)
#1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:4646:6)
#2 _InheritedProviderScopeElement.markNeedsNotifyDependents (package:provider/src/inherited_provider.dart:577:5)
#3 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:381:24)
#4 AllUsersProvider.getAllUsers (package:chatgpt_pracrtce/providers/all_users_provider.dart:14:5)
#5 _UsersCategoryState.didChangeDependencies (package:chatgpt_pracrtce/screens/users/users_category.dart:50:59)
#6 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5119:11)
#7 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4944:5)
... Normal element mounting (214 frames)
#221 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)
#222 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6512:36)
#223 Element.updateChild (package:flutter/src/widgets/framework.dart:3682:18)
#224 RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:6041:32)
#225 MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:6537:17)
#226 Element.updateChild (package:flutter/src/widgets/framework.dart:3660:15)
#227 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4993:16)
#228 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5133:11)
An error you described in your question is comes because you've initialize your user array from provider during widget building process, for immediate widget or array filter updation you need to use value notifier. And make sure to avoid using setState cause it slower down your application it indirectly rebuild all widgets exists on class
Starts using value notifier to achiev this,
class ….{
ValueNotifier<int> varCategoryId = ValueNotifier(-1);
#override
void initState() {
super.initState();
varCategoryId.value = widget.categoryId;
varCategoryId.notifyListeners();
}
When you click on particular category set below code,
onTap: () {
varCategoryId.value = widget.categories?[index].id ?? 0;
varCategoryId.notifyListeners();
},
& for user update wrap code within ValueListenableBuilder,
Replace your line,
ShowUsersBasedOnCategory(categoryId: _categoryId)
with
ValueListenableBuilder(
valueListenable: varCategoryId,
builder: (context, _varCategoryId, child){
List<UsersData>? users = provider.userData?.where((user) => user.categoryId == _varCategoryId).toList();
return Expanded(
child: GridView.builder(
itemCount: users.length,
shrinkWrap: true,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
childAspectRatio: 7 / 5,
crossAxisCount: 2,
mainAxisSpacing: 15,
),
itemBuilder: (context, index) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Container(
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10),
),
child: Center(child: Text(users[index].firstName.toString())),
),
),
),
);
}
),
Related
When I am trying to display the data present in firebase realtime database. I am getting the error stating Exception caught by widgets library Incorrect use of ParentDataWidget.
class NotificationView extends StatefulWidget {
const NotificationView({Key key}) : super(key: key);
#override
State<NotificationView> createState() => _NotificationViewState();
}
class _NotificationViewState extends State<NotificationView> {
Map data;
List key;
#override
void initState() {
fetchData();
super.initState();
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Scaffold(
backgroundColor: Colors.white,
body: Container(
child: FutureBuilder(
future: fetchData(),
builder: (context, snapshot) {
if (data != null) {
return ListView.builder(
itemCount: data.values.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
child: Card(
margin: EdgeInsets.fromLTRB(15, 5, 15, 15),
color: Colors.yellow[100],
elevation: 10,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10)),
child: Container(
margin: EdgeInsets.fromLTRB(15, 5, 15, 15),
child: Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(data[key[index]]['title']),
SizedBox(height: size.height * 0.01),
Text(data[key[index]]['message']),
],
),
),
),
),
);
});
} else {
return Center(child: CircularProgressIndicator());
}
})));
}
fetchData() async {
var userId = SharedUtils.getString('UserId');
final ref = FirebaseDatabase.instance.ref();
final snapshot =
await ref.child('users/62cfc3faf3e5df6648d32684/inApp').get();
debugPrint(snapshot.key + 'KEyyyyyyyyyyyyyyyyyyyyy');
data = snapshot.value;
key = data.keys.toList();
debugPrint(
'Listttttttttttttttofffffffffffkeyyyyyyyyyyyyyy&&&77' + key.toString());
}
}
You are using "Expanded" as the child of the container which is wrong. Be aware that, you can use the "Expanded" widget only as the child of columns, rows, and flex. That's why you are getting this "Incorrect use of ParentDataWidget".
More details for Expanded widget.
'''
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(() {});
}
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(...) {}
}
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)));
},
I'm new in Flutter and try to load video from api, but video player is not working correctly. I have PageView in my Widget _buildFilmsMainPages() and each Page will get own video from api.
i'm getting error while data is loading: The following NoSuchMethodError was thrown building FutureBuilder>(dirty, state: _FutureBuilderState>#033d3):
The method '[]' was called on null.
Receiver: null
Tried calling:
After loading this error is gone.
when i tap on play (Floating Action Button) i see only first frame of video but sound is working.
when i tap on stop (Floating Action Button) first frame of video is gone but sound is still working.
class HomePage extends StatefulWidget {
HomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_ HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
VideoPlayerController _controller;
Future<void> _initializeVideoPlayerFuture;
bool isVideo = false;
int filmIndex = 0;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold (
body: SingleChildScrollView(
child: _buildFilmsMainPages(),
)
);
}
Widget _buildFilmsMainPages() =>
FutureBuilder(
future:getMoviesListByDay(date))),
builder: (BuildContext context, AsyncSnapshot snapshot) {
without this code i get error, but player isn't working
correctly anyway and i'm getting error while data is loading
_controller= VideoPlayerController.network
(snapshot.data[filmIndex].media!=null?
snapshot.data[filmIndex].media.elementAt(1)
:"https://flutter.github.io/assets-for-api-
docs/assets/videos/butterfly.mp4");
_initializeVideoPlayerFuture =_controller.initialize();
_controller.setLooping(true);
if (snapshot.data != null) {
return
Column(
children:<Widget> [
SizedBox(
height: 460.0,
child: PageView.builder(
pageSnapping: true,
itemCount: snapshot.data.length,
onPageChanged: (int index) {
setState(() {
filmIndex = index;
i thought i should write this code here
_controller = VideoPlayerController.network
(snapshot.data[filmIndex].media!=null?
snapshot.data[filmIndex].media.elementAt(1)
:"https://flutter.github.io/assets-for-api-
docs/assets/videos/butterfly.mp4");
_initializeVideoPlayerFuture =
_controller.initialize();
_controller.setLooping(true);
});
},
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Container(margin: const
EdgeInsets.symmetric(horizontal: 16.0),
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Container(
height: 250.0,
child: Stack(children: <Widget>[
Container(
child: GestureDetector(
child: isVideo ?
FutureBuilder(
future:_initializeVideoPlayerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return AspectRatio(
aspectRatio: 16.0 / 12.0,
child:VideoPlayer(_controller),
);
} else {
return Center(
child:
CircularProgressIndicator());
}
},
) :
FadeInImage.assetNetwork(
placeholder:
"assets/placeholder.jpg",
image:
snapshot.data[index].media!=null
? snapshot.data[index].media.elementAt(0): "",
fit: BoxFit.fill,
fadeInDuration:Duration(milliseconds: 50),
),
onTap: () =>
)
),
)
)
),
Row(children: <Widget>[
Container(
margin: const EdgeInsets.only(left: 16.0,
right: 16.0, top: 190.0),
height: 40.0,
width: 40.0,
child: FittedBox(
child: FloatingActionButton(
backgroundColor: Colors.white,
foregroundColor: Colors.black,
onPressed: () {
setState(() {
isVideo = !isVideo;
if (_controller.value.isPlaying) {
_controller.pause();
} else {
_controller.play();
}
});
},
child: Icon(_controller.value.isPlaying
? Icons.pause : LineIcons.play,
size: 30.0,)
),
)
);