In today’s fast-paced world, staying informed is essential, and mobile applications have become a popular medium for accessing news. In this article, we’ll guide you through building a News Reader App step by step using Flutter, a powerful and versatile framework for creating cross-platform applications.
Flutter, developed by Google, allows developers to create natively compiled applications for mobile, web, and desktop from a single codebase. In this tutorial, we’ll leverage Flutter to build a News Reader App that fetches real-time news data from the NewsAPI and presents it in an intuitive and user-friendly manner.
Prerequisites
Before we dive into the implementation, make sure Flutter is installed on the system or download it from the official Flutter website. Also, ensure that a code editor is installed, such as Visual Studio Code or Android Studio.
Step-by-Step Implementation
Step 1: Project Setup
Start by creating a new Flutter project using the following command in the terminal or command prompt:
flutter create news_reader_app
Step 2: Add dependencies to Project
From terminal, add http package to project using following command
flutter pub add http url_launcher
Step 3: Import packages
First, we need to import installed packages before using them to avoid errors.
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart' ;
|
Step 4: News Class
The News class represents a news article with properties like title, image (URL to the article image), content, and url (URL to the full article).
class News {
final String title;
final String image;
final String content;
final String url;
News({required this .title, required this .image, required this .content, required this .url});
factory News.fromJson(Map<String, dynamic> json) {
return News(
title: json[ 'title' ],
image: json[ 'urlToImage' ],
content: json[ 'content' ],
url: json[ "url" ]
);
}
} |
Step 5: NewsCard Widget
The NewsCard widget is responsible for displaying individual news articles. It uses the ExpansionTile widget to expand and show the article content when tapped. The _launchURL function uses the url_launcher package to open the full article in a web browser if running application on browser, and on emulator browser if running on emulator.
class NewsCard extends StatelessWidget {
final News news;
NewsCard({required this .news});
void _launchURL(String url) async {
final Uri _url = Uri.parse(url);
if (!await launchUrl(_url,mode: LaunchMode.inAppWebView)) {
throw 'Could not launch $url' ;
}
}
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(8.0),
child: ExpansionTile(
leading: Image.network(news.image),
title: Text(news.title,style:
TextStyle(color: Colors.green,fontSize: 16,
fontWeight: FontWeight.w400),),
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: Text(
news.content,
style: TextStyle(fontSize: 16.0),
),
),
InkWell(
child: Text( "Read More" ,style: TextStyle(color: Colors.blue,height: 3),),
onTap: (){
_launchURL(news.url);
}
)
],
),
);
}
} |
Step 6: MyApp Widget
The MyApp widget is the root of our application. It fetches news data from the NewsAPI using an API key and displays the news articles using the ListView.builder widget.
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
_getNewsData();
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gfg News Reader App' ,
debugShowCheckedModeBanner: false ,
home: Scaffold(
backgroundColor: const Color.fromARGB(255, 202, 242, 203),
appBar: AppBar(
title: Text( 'Gfg News Reader App' ),
backgroundColor: Colors.green,
),
body: _news==null ? CircularProgressIndicator() :ListView.builder(
itemCount: _news.length,
itemBuilder: (context, index) {
return NewsCard(news: _news[index]);
},
),
),
);
}
} |
Step 7: Fetching News Data
Define The _getNewsData function inside MyApp widget to make an HTTP GET request to the NewsAPI endpoint, processes the JSON response, and populates the _news list with News objects.
Future< void > _getNewsData() async {
http.Response newsResponse;
String apiKey = "YOUR_API_KEY" ;
String urlString =
Uri uri = Uri.parse(urlString);
newsResponse = await http.get(uri);
if (newsResponse.statusCode == 200) {
Map<String, dynamic> jsonData = json.decode(newsResponse.body);
if (jsonData[ 'articles' ] != null) {
List<dynamic> articles = jsonData[ 'articles' ];
_news = articles.map((json) => News.fromJson(json)).toList();
} else {
throw Exception( 'No articles found in the response' );
}
} else {
throw Exception( 'Failed to load news' );
}
} |
Complete Code
Below is the complete code of news reader app
import 'package:flutter/material.dart' ;
import 'package:http/http.dart' as http;
import 'dart:convert' ;
import 'dart:core' ;
import 'package:url_launcher/url_launcher.dart' ;
void main() => runApp(MyApp());
class News {
final String title;
final String image;
final String content;
final String url;
News({required this .title, required this .image, required this .content, required this .url});
factory News.fromJson(Map<String, dynamic> json) {
return News(
title: json[ 'title' ],
image: json[ 'urlToImage' ],
content: json[ 'content' ],
url: json[ "url" ]
);
}
} class NewsCard extends StatelessWidget {
final News news;
NewsCard({required this .news});
void _launchURL(String url) async {
final Uri _url = Uri.parse(url);
if (!await launchUrl(_url,mode: LaunchMode.inAppWebView)) {
throw 'Could not launch $url' ;
}
}
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(8.0),
child: ExpansionTile(
leading: Image.network(news.image),
title: Text(news.title,style:
TextStyle(color: Colors.green,fontSize: 16,
fontWeight: FontWeight.w400),),
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: Text(
news.content,
style: TextStyle(fontSize: 16.0),
),
),
InkWell(
child: Text( "Read More" ,style: TextStyle(color: Colors.blue,height: 3),),
onTap: (){
_launchURL(news.url);
}
)
],
),
);
}
} class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
} class _MyAppState extends State<MyApp> {
List<News> _news = [];
@override
void initState() {
super.initState();
_getNewsData();
}
Future< void > _getNewsData() async {
http.Response newsResponse;
String apiKey = "YOUR_API_KEY" ;
String urlString =
Uri uri = Uri.parse(urlString);
newsResponse = await http.get(uri);
if (newsResponse.statusCode == 200) {
Map<String, dynamic> jsonData = json.decode(newsResponse.body);
if (jsonData[ 'articles' ] != null) {
List<dynamic> articles = jsonData[ 'articles' ];
_news = articles.map((json) => News.fromJson(json)).toList();
} else {
throw Exception( 'No articles found in the response' );
}
} else {
throw Exception( 'Failed to load news' );
}
} @override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Gfg News Reader App' ,
debugShowCheckedModeBanner: false ,
home: Scaffold(
backgroundColor: const Color.fromARGB(255, 202, 242, 203),
appBar: AppBar(
title: Text( 'Gfg News Reader App' ),
backgroundColor: Colors.green,
),
body: _news==null ? CircularProgressIndicator() :ListView.builder(
itemCount: _news.length,
itemBuilder: (context, index) {
return NewsCard(news: _news[index]);
},
),
),
);
}
} |
How to Run the App
To run the app, make sure you have Flutter installed and an emulator/device set up. Navigate to the project directory using the terminal and run the following command:
flutter run
This command will build and launch the app on your emulator/device.
Output:
Congratulations! You’ve successfully built a News Reader App with Flutter. This app can be further enhanced by adding features such as category filtering, search functionality, or saved articles.