Hello Guys, In this post we are going to learn how to integrate Network calls in Flutter
Here i am using the NewsAPI to fetch the news headlines. News API is a simple HTTP REST API for searching and retrieving live articles from all over the web
to Call api in Flutter we need to add
https: ^0.12.0+2 dependencies in the pubspec.yaml file
Now comming to dart classes
Create a RouteSetting Page to handle the Navigation B/W different screens.
routes.dart
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:newsapp/ui/categorylist.dart';
import 'package:newsapp/ui/newslist.dart';
import 'package:newsapp/ui/splash.dart';
class RouteSettngsPage extends RouteSettings{
static RoutegenerateRoute(RouteSettings settings){
var args=settings.arguments;
switch(settings.name){
case "/":
return MaterialPageRoute(builder: (_)=>SplashPage());
break;
case "/category":
return MaterialPageRoute(builder: (_)=>NewsCategory());
break;
case "/news":
HashMapreq=args as HashMap;
return MaterialPageRoute(builder: (_)=>News(req['category']));
break;
};
}
}
|
Splash Screen
splash.dart
import 'package:flutter/material.dart';
class SplashPage extends StatefulWidget{
@override
State createState() {
// TODO: implement createState
return SplashState();
}
}
class SplashState extends State{
@override
void initState() {
// TODO: implement initState
super.initState();
Future.delayed(Duration(seconds: 3),(){
Navigator.pushReplacementNamed(context, "/category");
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Container(
//child: Future.delayed(Duration(seconds: 2),(){});
child: Image.asset("splash_img.png",fit: BoxFit.cover,),
));
}
}
|
here we added background image in the splash screen. for this we need to
add in assets folder and configure the path in pubspec.yaml file under assets path.
Future.delayed widget is used to load the Next screen after some time.
here have navigation the next screen after 3 seconds
Future.delayed(Duration(seconds: 3),() {
Navigator.pushReplacementNamed(context, "/category");
});
With PushReplacementNamed function of Navigato class.
News Catergory List
categorylist.dart
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:newsapp/colors.dart';
import 'package:newsapp/model/newscategory.dart';
class NewsCategory extends StatefulWidget{
@override
State createState() {
// TODO: implement createState
return NewsCategorystate();
}
}
class NewsCategorystate extends State{
static const _appPrimaryValue = Color(0xFF009688);
ListlistNews;
ListlistNewsAll;
Icon _searchIcon = new Icon(Icons.search);
Widget _appBarTitle = new Text( 'Search Example' );
TextEditingController searchController=new TextEditingController();
@override
void initState() {
// TODO: implement initState
super.initState();
listNews=new List();
listNewsAll=new List();
fetchNews();
_searchPressed();
searchController.addListener((){
print(searchController.text);
if (searchController.text.isEmpty) {
setState(() {
listNews.clear();
listNews.addAll(listNewsAll);
});
} else {
setState(() {
listNews.clear();
for(int k=0;k0)?ListView.builder(
itemCount: listNews.length,
itemBuilder: (ctx,index){
return setNewsItem(listNews[index]);
}):Center(child: CircularProgressIndicator(),),
);
}
setNewsItem(NewsCategoryModel newsModel)
{
return Card(
elevation: 5,
child: Container(
margin: EdgeInsets.all(5),
padding: EdgeInsets.all(5),
child: InkWell(
onTap: (){
HashMaphm=new HashMap();
hm['category']=newsModel.category;
Navigator.pushNamed(context, "/news",arguments: hm);
},
child: Row(
children: [
Container(
height: 50,
width: 50,
decoration: ShapeDecoration(shape: CircleBorder(),
color: Colors.green[700]),child: Center(
child: Text(newsModel.name.substring(0,1).toUpperCase(),
style: TextStyle(fontSize: 30,color: Colors.white),)),
),
SizedBox(width:15,),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(newsModel.name,style: TextStyle(fontSize: 18,
color: Colors.black),),
SizedBox(height:5,),
Text(newsModel.description,style: TextStyle(fontSize: 12,
color: Colors.grey[800]),maxLines: 3,),
],
),
)
],),
),),
);
}
fetchNews(){
var callNews = NewsCategoryModel.callNewsCAtegory();
callNews.then((data){
var response=json.decode(data.body );
var listNewsdata=response['sources']as List;
setState(() {
listNews=listNewsdata.map((model)=>NewsCategoryModel
.fromJson(model))
.toList();
listNewsAll.clear();
listNewsAll.addAll(listNews);
});
},onError: (error){
print("Result Error $error");
}
);
}
void _searchPressed() {
setState(() {
if (this._searchIcon.icon == Icons.search) {
this._searchIcon = new Icon(Icons.close);
this._appBarTitle = new TextField(
controller: searchController,
decoration: new InputDecoration(
prefixIcon: new Icon(Icons.search),
hintText: 'Search...'
),
);
} else {
this._searchIcon = new Icon(Icons.search);
this._appBarTitle = new Text('Search Example');
searchController.clear();
}
});
}
}
|
Here i am calling the api in NewsCategoryModel file.
with get('https://newsapi.org/v2/sources?apiKey=YOUR_NEWSAPI_KEY&page=1');
The NewsCategoryModel file looks like below
import 'package:flutter/material.dart';
import 'package:http/http.dart' show get;
class NewsCategoryModel {
String id;
String name;
String description;
String url;
String category;
String language;
String country;
NewsCategoryModel(this.id,this.name,this.description,this.url,
this.category,this.language,this.country);
NewsCategoryModel.fromJson(MapparseModel)
{
id=parseModel['id'];
name=parseModel['name'];
description=parseModel['description'];
url=parseModel['url'];
category=parseModel['category'];
language=parseModel['language'];
country=parseModel['country'];
}
static Future callNewsCAtegory() async{
return get('https://newsapi.org/v2/sources?apiKey=PUT_YOUR_NEWSAPI_KEY&page=1');
//return get('https://jsonplaceholder.typicode.com/photos');
}
}
|
in initState() method calling the API.
For the AppBar we are passing the childs dynamically based on Search Icon events.
AppBar(title: _appBarTitle,
leading: IconButton(icon: this._searchIcon, onPressed: (){
_searchPressed();
}),
|
_appBarTitle & _searchIcon will modify on _searchPressed() function call.
For display each NewsCategory i have created card widget in setNewsItem() function
On Tap oneach Inkwell widget inside card will navigate to NewsList screen,
where we are passing the category name as argumnets to Navigator.pushedName like below
HashMaphm=new HashMap();
hm['category']=newsModel.category;
Navigator.pushNamed(context, "/news",arguments: hm);
|
The NewsList screen wich shows the news headlines for each category.
newslist.dart file
import 'dart:collection';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:newsapp/model/newsmodel.dart';
class News extends StatefulWidget{
String category;
News(this.category);
@override
State createState() {
// TODO: implement createState
return CategoryState();
}
}
class CategoryState extends State{
ListlistNews=[];
bool hasPages=true;
ScrollController _scrollController = new ScrollController();
int page=1;
@override
void initState() {
fetchnews();
super.initState();
_scrollController.addListener(() {
if(!hasPages)
{
return;
}
if (_scrollController.position.pixels ==
_scrollController.position.maxScrollExtent) {
page=page+1;
fetchnews();
}
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(title: Text(widget.category.toUpperCase()),),
body: listNews.length>0?ListView.builder(
itemCount: (hasPages)?listNews.length+1:listNews.length,
itemBuilder: (ctx,index){
if(index==listNews.length)
return Center(child: Container(width:50,height: 50,
child: CircularProgressIndicator()));
else
return setNewsItem(listNews[index]);
},controller: _scrollController,
):Center(child: CircularProgressIndicator(),),
);
}
fetchnews(){
var request=NewsModel.callNews(widget.category,page);
request.then((data){
var resdata=json.decode(data.body);
String status=resdata['status'];
hasPages=true;
var listdata=resdata["articles"] as List;
setState(() {
if(status=="ok") {
for (int k = 0; k < listdata.length; k++) {
NewsModel myModel = NewsModel();
myModel.author = listdata[k] ['author'];
myModel.title = listdata[k] ['title'];
myModel.description = listdata[k] ['description'];
myModel.url = listdata[k] ['url'];
myModel.urlToImage = listdata[k] ['urlToImage'];
myModel.publishedAt = listdata[k] ['publishedAt'];
myModel.content = listdata[k] ['content'];
listNews.add(myModel);
}
}
else
{
hasPages=false;
}
});
},onError: (error){
hasPages=false;
});
}
setNewsItem(NewsModel newsModel)
{
return Card(
elevation: 5,
child: Container(
margin: EdgeInsets.all(5),
padding: EdgeInsets.all(5),
child: InkWell(
onTap: (){
},
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(newsModel.title,style:
TextStyle(fontSize: 18,color: Colors.black),),
SizedBox(height:5,),
FadeInImage(placeholder: AssetImage("flutter_big.png"),
height:200,fit: BoxFit.cover,
image: NetworkImage(newsModel.urlToImage,) ),
SizedBox(height:5,),
Text((newsModel.content==null)?"":newsModel.content,
style: TextStyle(fontSize: 12,color: Colors.grey[800]),maxLines: 3,),
],
)
),),
);
}
}
|
The Routing the each page is handle from main.dart file with
MaterialApp widget onGenerateRoute property.
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
onGenerateRoute: RouteSettngsPage.generateRoute,
);
}
}
|
You can find complete code at rrtutors github account
Article Contributed By :
|
|
|
|
7369 Views |