Flutter Error: Use api in tabbar and tabbarView? - flutter

I want to fetch data from API and use the data in tabbar and tabview.
I want to create (Ayurved app), I have a list of subcategory in the api, I followed this documentation, so I need to add api's subcategory to my TabBar.
So How can I do that? I don't understand how this will happen.
This is my Tab Page.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:hospital/customApiVariable.dart';
import 'package:http/http.dart' as http;
class TabPage extends StatefulWidget {
final medicineCatUniqId;
const TabPage({Key key, this.medicineCatUniqId}) : super(key: key);
// const TabPage({Key key}) : super(key: key);
#override
_TabPageState createState() => _TabPageState();
}
class _TabPageState extends State<TabPage> {
var response;
var medicineSubCategoryApi;
#override
void initState() {
// TODO: implement initState
//
super.initState();
// for loading
fetchData(widget.medicineCatUniqId);
}
fetchData(var medicineCatUniqId) async {
a2rTokenKey=carpet1234');
var api = Uri.parse(
'$baseUrl/productSubCatApi.php?a2rTokenKey=$a2rTokenKey&pcat=$medicineCatUniqId');
response = await http.get(
api,
);
print("medicineCatApiLnk " + api.toString());
print("medicineCat" + response.body);
medicineSubCategoryApi = jsonDecode(response.body);
print("medicineCatString" + medicineSubCategoryApi.toString());
setState(() {});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: DefaultTabController(
length: medicineSubCategoryApi.length,
child: Scaffold(
appBar: AppBar(
title: const Text('Tabbed AppBar'),
bottom: TabBar(
isScrollable: true,
tabs: medicineSubCategoryApi.map((choice) {
return Tab(
text: choice.psubCatName,
icon: Icon(choice),
);
}).toList(),
),
),
body: TabBarView(
children: medicineSubCategoryApi.map<Widget>((choice) {
return Padding(
padding: const EdgeInsets.all(20.0),
child: ChoicePage(
choice: choice,
),
);
}).toList(),
),
),
),
);
}
}
class ChoicePage extends StatelessWidget {
const ChoicePage({Key key, this.choice}) : super(key: key);
final choice;
#override
Widget build(BuildContext context) {
final TextStyle textStyle = Theme.of(context).textTheme.display1;
return Card(
color: Colors.white,
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// Icon(
// choice,
// size: 150.0,
// color: textStyle.color,
// ),
Text(
choice.psubCatName,
style: textStyle,
),
],
),
),
);
}
}
This is my Api Data.
[{"psubCatUniq":"60c464556cd04","psubCatName":"TURMERIC CAPSULES","psubCatDescrition":"TURMERIC CAPSULES","psubCatImg":"http:\/\/a2rstore.com\/inventory\/images\/subCategory-bb.jpg","psubCatIcon":"","psubCatDate":"","psubCatlink":"list.php?subName=TURMERIC CAPSULES&sub=60c464556cd04","pcatUniq":"60c462501a664","pcatName":"Herbal Tablets"},{"psubCatUniq":"60c464360de3f","psubCatName":"PAIN CALM TABLET","psubCatDescrition":"PAIN CALM TABLET","psubCatImg":"http:\/\/a2rstore.com\/inventory\/images\/subCategory-aa.jpg","psubCatIcon":"","psubCatDate":"","psubCatlink":"list.php?subName=PAIN CALM TABLET&sub=60c464360de3f","pcatUniq":"60c462501a664","pcatName":"Herbal Tablets"}]

You can use a FutureBuilder widget to make the API call then access the data you require from the response data to create the Tabs.
A Simple Example
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder(
future: fetchData(widget.medicineCatUniqId),
builder: (context, snapshot) {
if (snapshot.hasData) {
// API data will be stored as snapshot.data
return DefaultTabController(
// Your Widget UI here ( Copy & paste ) what you have above
);
} else if (snapshot.hasError) {
return Text('Error');
} else {
return Text('Loading');
}
}
),
);
}
You will also need to update fetchData() to return the value to FutureBuilder:
fetchData(var medicineCatUniqId) async {
var api = Uri.parse(
'$baseUrl/productSubCatApi.php?a2rTokenKey=$a2rTokenKey&pcat=$medicineCatUniqId');
response = await http.get(
api,
);
print("medicineCatApiLnk " + api.toString());
print("medicineCat" + response.body);
medicineSubCategoryApi = jsonDecode(response.body);
print("medicineCatString" + medicineSubCategoryApi.toString());
//setState(() {});
return medicineSubCategoryApi;
}

Related

API data not showing in flutter dropdown

i am trying to display data list API to dropdown but the result is not there, which i have to fix.
I'm trying to change or update user data and have some data in the form of a list including the user being able to choose country, religion, and others. among these
how do i make it.
fetch API
Future<UserBiodata> getBiodata() async {
String url = Constant.baseURL;
String token = await UtilSharedPreferences.getToken();
final response = await http.get(
Uri.parse(
'$url/auth/mhs_siakad/biodata',
),
headers: {
'Authorization': 'Bearer $token',
},
);
print(response.statusCode);
print(response.body);
if (response.statusCode == 200) {
return UserBiodata.fromJson(jsonDecode(response.body));
} else {
throw Exception('Token Expired!');
}
}
show in widget
String? _mySelection;
List<Agama> agama = [];
#override
void initState() {
super.initState();
BiodataProvider().getBiodata();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: PreferredSize(
preferredSize: const Size.fromHeight(kToolbarHeight),
child: CustomAppbar(
title: 'Edit Biodata',
),
),
body: Padding(
padding: const EdgeInsets.all(18),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.only(left: 12, right: 8),
width: double.infinity,
height: 50,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.2),
spreadRadius: 1,
blurRadius: 9,
offset: const Offset(
1,
2,
),
),
],
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
items: agama.map((item) {
return DropdownMenuItem<String>(
value: item.nmAgama,
child: Text(item.nmAgama),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal!;
});
},
value: _mySelection,
),
),
),
using StateManagement or FutureBuilder to receive async data from Future function (BiodataProvider().getBiodata();)
read more at: https://dart.dev/codelabs/async-await
https://docs.flutter.dev/development/data-and-backend
you are using List<Agama> agama = []; to display the dropdown items, but you are not adding data to your agama list.
So, add the proper data into your agama list which you are getting from API.
And don't forget to do setState((){}) after adding data into agama list because you are not using any state management.
Here is a full example like you want.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter DropDownButton',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: const MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String? dropdownvalue;
Future<List<String>> getAllCategory() async {
var baseUrl = "https://gssskhokhar.com/api/classes/";
http.Response response = await http.get(Uri.parse(baseUrl));
if (response.statusCode == 200) {
List<String> items = [];
var jsonData = json.decode(response.body) as List;
for (var element in jsonData) {
items.add(element["ClassName"]);
}
return items;
} else {
throw response.statusCode;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("DropDown List"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
FutureBuilder<List<String>>(
future: getAllCategory(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var data = snapshot.data!;
return DropdownButton(
// Initial Value
value: dropdownvalue ?? data[0],
// Down Arrow Icon
icon: const Icon(Icons.keyboard_arrow_down),
// Array list of items
items: data.map((String items) {
return DropdownMenuItem(
value: items,
child: Text(items),
);
}).toList(),
// After selecting the desired option,it will
// change button value to selected value
onChanged: (String? newValue) {
setState(() {
dropdownvalue = newValue!;
});
},
);
} else {
return const CircularProgressIndicator();
}
},
),
],
),
),
);
}
}

pass value between bottomNavigationBar views

How am I supposed to pass a value in this big mess called Flutter?
30 years old php global $var wasn't good?
All these years were to come up with setState, passed in a controller which get redeclared as a key inside a stateful widget that receive the value from a Navigator?
By the way, I tried using Navigator.push but it seems to open a completely new window, the value is there but I'd need it to show in the tab body not in a new window, below is my code:
main.dart
import 'dart:core';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomeView(),
);
}
}
class HomeView extends StatefulWidget {
#override
_HomeViewState createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
final tabs = [QRViewExample(), SecondView(res: '')];
int _currentIndex = 0;
#override
void initState() {
setState(() {});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
toolbarHeight: 40.0,
elevation: 0,
centerTitle: true,
title: Text('Flutter App'),
),
body: tabs[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.red,
currentIndex: _currentIndex,
type: BottomNavigationBarType.fixed,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white.withOpacity(0.5),
items: [
BottomNavigationBarItem(
icon: Icon(Icons.qr_code),
label: 'Scan',
),
BottomNavigationBarItem(
icon: Icon(Icons.list),
label: 'List',
),
],
onTap: (index) {
setState(() {
_currentIndex = index;
});
},
),
);
}
}
// SECOND TAB WIDGET (custom)
class SecondView extends StatelessWidget {
const SecondView({Key? key, required this.res}) : super(key: key);
final String? res;
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: Text(res!),
),
);
}
}
// FIRST TAB WIDGET (qrcode)
class QRViewExample extends StatefulWidget {
const QRViewExample({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _QRViewExampleState();
}
class _QRViewExampleState extends State<QRViewExample> {
Barcode? result;
QRViewController? controller;
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
#override
void reassemble() {
super.reassemble();
if (Platform.isAndroid) {
controller!.pauseCamera();
}
controller!.resumeCamera();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: 500,
child: Padding(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Expanded(flex: 4, child: _buildQrView(context)),
Expanded(
flex: 1,
child: FittedBox(
fit: BoxFit.contain,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
if (result != null)
Text(
'Barcode Type: ${describeEnum(result!.format)} Data: ${result!.code}')
else
const Text('Scan a code'),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.toggleFlash();
setState(() {});
},
child: FutureBuilder(
future: controller?.getFlashStatus(),
builder: (context, snapshot) {
return Text('Flash: ${snapshot.data}');
},
)),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.flipCamera();
setState(() {});
},
child: FutureBuilder(
future: controller?.getCameraInfo(),
builder: (context, snapshot) {
if (snapshot.data != null) {
return Text(
'Camera facing ${describeEnum(snapshot.data!)}');
} else {
return const Text('loading');
}
},
)),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.pauseCamera();
},
child: const Text('pause',
style: TextStyle(fontSize: 20)),
),
),
Container(
margin: const EdgeInsets.all(8),
child: ElevatedButton(
onPressed: () async {
await controller?.resumeCamera();
},
child: const Text('resume',
style: TextStyle(fontSize: 20)),
),
)
],
),
],
),
),
)
],
),
),
),
);
}
Widget _buildQrView(BuildContext context) {
var scanArea = (MediaQuery.of(context).size.width < 400 ||
MediaQuery.of(context).size.height < 400)
? 150.0
: 300.0;
return QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
overlay: QrScannerOverlayShape(
borderColor: Colors.cyanAccent,
borderRadius: 10,
borderLength: 30,
borderWidth: 10,
cutOutSize: scanArea),
onPermissionSet: (ctrl, p) => _onPermissionSet(context, ctrl, p),
);
}
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
});
controller.scannedDataStream.listen((scanData) {
controller.pauseCamera();
setState(() {
result = scanData;
});
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondView(res: result!.code)))
.then((value) => controller.resumeCamera());
});
}
void _onPermissionSet(BuildContext context, QRViewController ctrl, bool p) {
log('${DateTime.now().toIso8601String()}_onPermissionSet $p');
if (!p) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('no Permission')),
);
}
}
#override
void dispose() {
controller?.dispose();
super.dispose();
}
}
How am I supposed to pass a value in this big mess called Flutter?
With state management tools like InheritedWidget, InheritedModel, Provider, BloC and many more.
30 years old php global $var wasn't good? All these years were to come up with setState, passed in a controller which get redeclared as a key inside a stateful widget that receive the value from a Navigator?
Well, you shouldn't do that and it's not meant to be done like that. We can use several methods to propagate data down the widget tree. Let me explain this with InheritedWidget. But sometimes you want to go for Provider which is a wrapper class for InheritedWidget.
First we create a class named QRListModel which extends InheritedModel:
class QRListModel extends InheritedWidget {
final List<Barcode> qrList = []; // <- This holds our data
QRListModel({required super.child});
#override
bool updateShouldNotify(QRListModel oldWidget) {
return !listEquals(oldWidget.qrList, qrList);
}
static QRListModel of(BuildContext context) {
final QRListModel? result = context.dependOnInheritedWidgetOfExactType<QRListModel>();
assert(result != null, 'No QRListModel found in context');
return result!;
}
}
updateShouldNotify is a method we have to override to tell Flutter, when we want the widgets to rebuild. We want this to happen when the list changes. The of method is just a handy way to access the QRListModel.
Now wrap a parent widget of both the scan tab view and the list tab view inside QRListModel. We go for HomeView:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter App',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: QRListModel(child: HomeView()), // <- here!
);
}
}
We can take any parent widget but it should be a class where we don't call setState. Otherwise our QRListModel also gets rebuilt and our list is gone.
Now we can access QRListModel from anywhere inside the subtree. We need it here:
void _onQRViewCreated(QRViewController controller) {
setState(() {
this.controller = controller;
this.controller!.resumeCamera();
});
controller.scannedDataStream.listen((scanData) async {
controller.pauseCamera();
QRListModel.of(context).qrList.add(scanData); // <- Here we access the list
await showDialog(
context: context,
builder: (context) => SimpleDialog(
title: Text("Barcode was added!"),
children: [
Text(scanData.code!)
],
)
);
});
}
And here we read the list:
class SecondView extends StatelessWidget {
const SecondView({Key? key, required this.res}) : super(key: key);
final String? res;
#override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: QRListModel.of(context).qrList.length,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text(QRListModel.of(context).qrList[index].code ?? "NO"),
),
);
}
);
}
}
Now both pages have access to the qr list. Please do mind that a InheritedWidget can only have final fields. So if you need mutable fields, you need an additional wrapper class. We don't need it as we don't change the list but only its elements.
By the way: You shouldn't call setState inside initState. You did this here:
class _HomeViewState extends State<HomeView> {
final tabs = [QRViewExample(), SecondView(res: '')];
int _currentIndex = 0;
#override
void initState() {
setState(() {}); // <- Don't call setState inside initState!
super.initState();
}

Screen goes blank if I search for something in TextField that is out of my list

I have created a list in another directory which is a list of JSON data and I have showed it on screen and also added a TextField which works as a search bar. it works fine if I search for a letter(or combination of letters) that is inside my list but when I search for something out of list the whole page goes blank except for the Appbar.
here's my code:
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:flutter/services.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
// Hide the debug banner
debugShowCheckedModeBanner: false,
title: 'Kindacode.com',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List _items = [];
List _itemsForDisplay = [];
// Fetch content from the json file
Future<void> readJson() async {
final String response = await rootBundle.loadString('assets/Symptoms.json');
final data = await json.decode(response);
setState(() {
_items = data["Symptoms"];
_itemsForDisplay = _items;
});
}
#override
void initState() {
// TODO: implement initState
readJson();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text(
'Diagnose',
),
),
body: Padding(
padding: const EdgeInsets.all(25),
child: Column(
children: [
// Display the data loaded from sample.json
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return index == 0 ? _searchBar() : _ListItem(index);
},
itemCount: _itemsForDisplay.length,
),
)
],
),
),
);
}
_searchBar() {
return Padding(
padding: const EdgeInsets.all(8),
child: TextField(
decoration: InputDecoration(hintText: 'Search'),
onChanged: (text) {
text = text.toLowerCase();
setState(() {
_itemsForDisplay = _items.where((item) {
var itemTitle = item.toLowerCase();
return itemTitle.contains(text);
}).toList();
});
},
),
);
}
_ListItem(index) {
return Card(
margin: const EdgeInsets.all(10),
child: ListTile(
leading: Text(_itemsForDisplay[index]),
),
);
}
}
Here's a picture before for searching for something that is an entity of my list
and this happens when I search for "." or anything that is not in my list:
In your item builder return only _ListItem(index) and put _searchBar outside of Expanded. In current code, you are skipping first element from list and showing search bar instead, which is wrong. That's why when length of list is 0 you don't see anything. Because builder doesn't get executed.
So, your built method should look like this:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text(
'Diagnose',
),
),
body: Padding(
padding: const EdgeInsets.all(25),
child: Column(
children: [
// Display the data loaded from sample.json
_searchBar(),
Expanded(
child: ListView.builder(
itemBuilder: (context, index) {
return _ListItem(index);
},
itemCount: _itemsForDisplay.length,
),
)
],
),
),
);
}

How to Get ALL cache from Api Cache Manager?

I'm using api_cache_manager: ^1.0.2
How to get all cache?
Because i'm need all cache and showing in list
please someone help me
API Cache Manager is a Utility package built with Flutter SDK and
SQLite Package. This package will help to make your Rest API store in
the local db for offline access.
import
import 'package:api_cache_manager/api_cache_manager.dart';
import 'package:api_cache_manager/models/cache_db_model.dart';
import 'package:api_cache_manager/utils/cache_db_helper.dart';
This will provide all cached data
List<Map<String,dynamic>> list = await APICacheDBHelper.query(APICacheDBModel.table);
OR
List<Map<String,dynamic>> list =await APICacheDBHelper.rawQuery("select * from ${APICacheDBModel.table}");
This will create dummy data and save in cache and return all data from the cache
Future<List<Map<String, dynamic>>> fetchapiCach() async {
// await APICacheDBHelper.deleteAll(APICacheDBModel.table);
var lists = new List<int>.generate(10, (i) => i + 1);
lists.forEach((element) async {
var cacheData2 = await APICacheManager().addCacheData(new APICacheDBModel(
syncData: '{"name":"lava$element"}',
key: "$element",
));
});
List<Map<String,dynamic>> list = await APICacheDBHelper.query(APICacheDBModel.table);
// await APICacheDBHelper.rawQuery("select * from ${APICacheDBModel.table}");
return list;
}
SampleCode
import 'package:api_cache_manager/api_cache_manager.dart';
import 'package:api_cache_manager/models/cache_db_model.dart';
import 'package:api_cache_manager/utils/cache_db_helper.dart';
import 'package:flutter/material.dart';
void main() {
// fetchapiCach();
runApp(const MyApp());
}
Future<List<Map<String, dynamic>>> fetchapiCach() async {
// await APICacheDBHelper.deleteAll(APICacheDBModel.table);
var lists = new List<int>.generate(10, (i) => i + 1);
lists.forEach((element) async {
var cacheData2 = await APICacheManager().addCacheData(new APICacheDBModel(
syncData: '{"name":"lava$element"}',
key: "$element",
));
});
List<Map<String,dynamic>> list = await APICacheDBHelper.query(APICacheDBModel.table);
// await APICacheDBHelper.rawQuery("select * from ${APICacheDBModel.table}");
// print(list);
list.forEach((element) {
print(element);
});
return list;
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatelessWidget(),
),
),
);
}
}
class MyStatelessWidget extends StatelessWidget {
const MyStatelessWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: fetchapiCach(),
builder: (BuildContext context,
AsyncSnapshot<List<Map<String, dynamic>>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: Container(
height: 10, width: 10, child: CircularProgressIndicator()));
} else {
print(snapshot.data);
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
return ListTile(
title: Row(
children: [
Text(
"${snapshot.data![index]["key"]}",
style: TextStyle(fontSize: 25),
),
Expanded(
child: Align(
alignment: Alignment.topRight,
child: Text("${snapshot.data![index]["syncData"]}"),
)),
],
),
subtitle: Row(
children: [
Expanded(
child: Align(
alignment: Alignment.topRight,
child:
Text("${snapshot.data![index]["syncTime"]}")),
)
],
),
leading: CircleAvatar(),
);
});
}
;
});
}
}

The return type 'NewsModel' isn't a 'Widget' as required by the closure's context

I have been trying to build a News App that fetches data from the newsapi.org service and just when I am about to call the data inside the main method I am getting this error saying that my class 'NewsModel' isn't of the type 'Widget' as required by the closure's context. I have no idea what that means but here is my code for the app split into 2 files.
import 'package:flutter/material.dart';
import 'models/news_model.dart';
import 'news_service.dart';
import 'package:assgn_digia_tech/models/news_model.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _loading = true;
var newsList;
List<NewsModel> articles = [];
void getNews() async {
newsService apiNews = newsService();
await apiNews.getNews();
articles = apiNews.apiNews;
setState(() {
_loading = false;
});
}
#override
void initState() {
super.initState();
getNews();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
'News API',
style: TextStyle(
color: Colors.black,
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
backgroundColor: Colors.cyan[50],
// ignore: prefer_const_literals_to_create_immutables
actions: [
Padding(
padding: const EdgeInsets.only(right: 12.0),
child: IconButton(
icon: Icon(Icons.search, color: Colors.black, size: 26),
onPressed: () {},
),
),
],
),
body: SafeArea(
child: _loading
? Center(
child: CircularProgressIndicator(),
)
: SingleChildScrollView(
child: Container(
child: Column(
children: [
Container(
child: ListView.builder(
itemCount: articles.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return NewsModel(
title: articles[index].title,
description: articles[index].description,
author: articles[index].author,
content: articles[index].content,
urlToImage: articles[index].urlToImage,
);
},
),
),
],
),
),
),
),
),
);
}
}
import 'dart:convert';
import 'package:assgn_digia_tech/models/news_model.dart';
import 'package:http/http.dart' as http;
class newsService {
List<NewsModel> apiNews = [];
Future<void> getNews() async {
String apiUrl =
'https://newsapi.org/v2/top-headlines?country=in&apiKey=4e3474bb91ec49eda31b75e2daf6da3c';
var response = await http.get(Uri.parse(apiUrl));
var jsonData = jsonDecode(response.body);
if (response.statusCode == 200) {
jsonData['articles'].forEach((element) {
if (element['urlToImage'] != null && element['description'] != null) {
NewsModel article = NewsModel(
title: element['title'],
author: element['author'],
description: element['description'],
urlToImage: element['urlToImage'],
content: element["content"],
);
apiNews.add(article);
}
});
}
}
}
itemBuilder: (context, index) {
return NewsModel(
You are supposed to return a Widget from the builder, because the purpose is to build a UI. Do you have a custom "NewsWidget" here, or do you want to build it from scratch? Maybe start by returning Text(articles[index].title) and then building it up from there to include all the other parts of your NewsModel.