How to update state of a ModalBottomSheet in Flutter? - flutter

This code is very simple: shows a modal bottom sheet and when the uses clicks the button, it increases the height of the sheet by 10.
But nothing happens. Actually, it only updates its size if the user "slides" the bottom sheet with it's finger (I belive that swipe causes a internal setState on the sheet).
My question is: how do I call the update state of a ModalBottomSheet?
showModalBottomSheet(
context: context,
builder: (context) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(
onPressed: () {
setState(() {
heightOfModalBottomSheet += 10;
});
}),
);
});

You can use Flutter's StatefulBuilder to wrap your ModalBottomSheet as follows:
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setState /*You can rename this!*/) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(onPressed: () {
setState(() {
heightOfModalBottomSheet += 10;
});
}),
);
});
});
Please note that the new setState will override your main widget setState but sure you can just rename it so you would be able to set state of your parent widget and the modal's
//This sets modal state
setModalState(() {
heightOfModalBottomSheet += 10;
});
//This sets parent widget state
setState(() {
heightOfModalBottomSheet += 10;
});

You can maybe use the showBottomSheet from the ScaffoldState. read more here about this showBottomSheet.
This will show the bottomSheet and return a controller PersistentBottomSheetController. with this controller you can call controller.SetState((){}) which will re-render the bottomSheet.
Here is an example
PersistentBottomSheetController _controller; // <------ Instance variable
final _scaffoldKey = GlobalKey<ScaffoldState>(); // <---- Another instance variable
.
.
.
void _incrementBottomSheet(){
_controller.setState(
(){
heightOfModalBottomSheet += 10;
}
)
}
.
void _createBottomSheet() async{
_controller = await _scaffoldKey.currentState.showBottomSheet(
context: context,
builder: (context) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(
onPressed: () {
_incrementBottomSheet()
}),
);
});
}

Screenshot:
Create a class:
class MyBottomSheet extends StatefulWidget {
#override
_MyBottomSheetState createState() => _MyBottomSheetState();
}
class _MyBottomSheetState extends State<MyBottomSheet> {
bool _flag = false;
#override
Widget build(BuildContext context) {
return Column(
children: [
FlutterLogo(
size: 300,
style: FlutterLogoStyle.stacked,
textColor: _flag ? Colors.black : Colors.red,
),
RaisedButton(
onPressed: () => setState(() => _flag = !_flag),
child: Text('Change Color'),
)
],
);
}
}
Usage:
showModalBottomSheet(
context: context,
builder: (_) => MyBottomSheet(),
);

Please refer to the below working code. I created a new Stateful widget(ModalBottomSheet) for the showModalBottomSheet. On button press, we are rebuilding the ModalBottomSheet only which is much cleaner now. We can use AnimationController if need animation for changing the height.
import 'dart:async';
import 'package:flutter/material.dart';
class ModalBottomSheet extends StatefulWidget {
_ModalBottomSheetState createState() => _ModalBottomSheetState();
}
class _ModalBottomSheetState extends State<ModalBottomSheet>
with SingleTickerProviderStateMixin {
var heightOfModalBottomSheet = 100.0;
Widget build(BuildContext context) {
return Container(
height: heightOfModalBottomSheet,
child: RaisedButton(
child: Text("Press"),
onPressed: () {
heightOfModalBottomSheet += 100;
setState(() {});
}),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return new _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
Future(() => showModalBottomSheet(
context: context,
builder: (context) {
return ModalBottomSheet();
}));
return new Scaffold(
appBar: new AppBar(
title: new Text("Modal example"),
),
);
}
}
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(title: 'Flutter Demo', home: new MyHomePage());
}
}

create a separate StatefulWidget for the showModalBottomSheet(), like
showModalBottomSheet(
context: context,
builder: (ctx) {
return MapBottomSheet();
});
Bottom Sheet Statefulwidget
class MapBottomSheet extends StatefulWidget {
#override
_MapBottomSheetState createState() => _MapBottomSheetState();
}
class _MapBottomSheetState extends State<MapBottomSheet> {
List<String> places = [];
void _setPlaces(String place) {
setState(() {
places.add(place);
});
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.black12,
child: Column(
children: [
AppTextField(
hint: "Search",
onEditingComplete: () {},
onChanged: (String text) {},
onSubmitted: (String text) async {
// Await the http get response, then decode the json-formatted response.
var response = await http.get(Uri.parse(
'https://api.mapbox.com/geocoding/v5/mapbox.places/$text.json?access_token=pk.eyJ1IjoidjNyc2lvbjkiLCJhIjoiY2ttNnZldmk1MHM2ODJxanh1ZHZqa2I3ZCJ9.e8pZsg87rHx9FSM0pDDtlA&country=PK&fuzzyMatch=false&place=park'));
if (response.statusCode == 200) {
Map<String, dynamic> data = jsonDecode(response.body);
print(data.toString());
List<dynamic> features = data['features'];
features.forEach((dynamic feature) {
setState(() {
_setPlaces(feature['place_name']);
});
});
} else {
print('Request failed with status: ${response.statusCode}.');
}
},
),
Expanded(
child: Container(
height: 250.0,
width: double.infinity,
child: ListView.builder(
itemCount: places.length,
itemBuilder: (ctx, idx) {
return Container(
child: Text(places[idx]),
);
}),
),
),
],
),
);
}
}

Related

setState() not updating UI elements even though the state variable, a Future, is updated?

I have a HomePage screen which has a FutureBuilder List implemented with a Future function as the state variable. I am updating this Future in another dart file by using keys to access the future. The Future gets updated and I'm sure of this as I've seen the print statements, but when I call the setState method, the UI doesn't show the newly added entry.
Here's my HomePage.dart:
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => HomePageState();
}
class HomePageState extends State<HomePage> {
Future<List<Model>> getData() async {
return await DatabaseHelper.instance.getModels();
}
Future? userFuture;
#override
void initState() {
super.initState();
userFuture = getData();
print(userFuture);
}
#override
Widget build(BuildContext context) {
print('Building listview');
return Center(
child: FutureBuilder<List<Model>>(
future: userFuture as Future<List<Model>>,
builder: ((context, AsyncSnapshot<List<Model>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return const CircularProgressIndicator();
default:
if (snapshot.data!.isEmpty) {
return Text('No data present');
} else if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((context, index) {
return MyCard(
key: ValueKey(snapshot.data![index].id),
snapshot.data![index].id,
snapshot.data![index].title,
snapshot.data![index].purpose);
}),
);
}
return Text('data');
}
}),
),
);
}
}
Here's my other dart file. Under the AddEntryState I'm updating the Future state variable and then right after calling the setState method.
class RootPage extends StatefulWidget {
const RootPage({super.key});
#override
State<RootPage> createState() => RootPageState();
}
class RootPageState extends State<RootPage> {
static final GlobalKey<HomePageState> homepageKey =
GlobalKey<HomePageState>();
int currentPage = 0;
List<Widget>? pages;
#override
void initState() {
super.initState();
pages = [
HomePage(key: homepageKey),
StatsPage(),
];
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('App Title'),
),
body: pages?[currentPage],
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => AddEntry()));
},
child: Icon(Icons.add),
),
bottomNavigationBar: NavigationBar(
destinations: [
NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
NavigationDestination(icon: Icon(Icons.data_usage), label: 'Stats'),
],
onDestinationSelected: (int index) {
setState(() {
currentPage = index;
print(index);
});
},
selectedIndex: currentPage,
),
);
}
}
class AddEntry extends StatefulWidget {
const AddEntry({super.key});
#override
State<AddEntry> createState() => _AddEntryState();
}
class _AddEntryState extends State<AddEntry> {
final GlobalKey<FormState> _key = GlobalKey<FormState>();
Map<String, String?> formField = <String, String?>{};
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('New Entry'),
),
body: Form(
key: _key,
child: Column(
children: [
Flexible(
child: MyTextField('Title', callback),
),
Flexible(
child: MyTextField('Purpose', callback),
),
Flexible(
child: MyTextField('Password', callback, obscure: true),
),
TextButton(
onPressed: () async {
if (_key.currentState!.validate()) {
_key.currentState?.save();
formField.forEach((label, value) => print('$label = $value'));
await DatabaseHelper.instance.insertModel(Model(
id: null,
title: formField['Title'],
purpose: formField['Purpose'],
lastAccess: DateTime.now().toString(),
dateAdded: DateTime.now().toString(),
password: formField['Password']));
print(await DatabaseHelper.instance.getModels());
// await DatabaseHelper.instance.deleteAllData();
// print(await DatabaseHelper.instance.getModels());
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('Data Saved!'),
action: SnackBarAction(
label: 'Edit',
onPressed: () {
print('edit pressed!');
},
),
),
);
Navigator.pop(context);
print("HomePage userFuture: ");
print(RootPageState.homepageKey.currentState!.userFuture!
.then((result) => print(result)));
print("getData function: ");
print(RootPageState.homepageKey.currentState!
.getData()
.then((result) => print(result)));
print("New Future: ");
print(RootPageState.homepageKey.currentState!.userFuture!
.then((result) => print(result)));
setState(() {
RootPageState.homepageKey.currentState!.userFuture =
RootPageState.homepageKey.currentState!.getData();
});
//add logic to rebuild home screen after every addition of entry
}
},
child: Text('Submit'),
),
],
),
),
);
}
callback(varLabel, varValue) {
formField[varLabel] = varValue;
}
}

NavigatorPush is not working on my Flutter App

I try to build simple login with laravel but then got stuck. After login success I can't redirect to another page with Navigator.push. I think I've followed the tutorial right.
this is login.dart
class LoginScreen extends StatefulWidget {
static const routeName = '/login-screen';
const LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController txtUsername = new TextEditingController();
TextEditingController txtPassword = new TextEditingController();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; //provide total height and width
return Scaffold(
body: Background(
child1: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Positioned(
top: 0,
left: 0,
child: Image.asset('assets/images/wedding.png', width: 250),
),
SizedBox(height: size.height * 0.01),
roundedInputField(
hintText: 'Email',
controller: txtUsername,
onChanged: (value) {},
),
PasswordField(
hintText: 'Password',
controller: txtPassword,
onChanged: (value) {},
),
Button(
text: 'LOGIN',
press: () {
this.doLogin();
},
)
],
),
),
),
);
}
void showToast(msg) => Fluttertoast.showToast(msg: msg);
Future doLogin() async {
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
if(txtUsername.text.isEmpty || txtPassword.text.isEmpty) {
showToast('email/password kosong');
}else {
showDialog(
context: context,
builder: (context) {
return Center(
child: CircularProgressIndicator(),
);
});
final response = await http.post(
Uri.parse('http://10.0.2.2/flutter/api/login'),
body: {'email': txtUsername.text, 'password': txtPassword.text},
headers: {'Accept': 'application/json'}
);
final responseData = json.decode(response.body);
if (response.statusCode == 200) {
showToast('berhasil login');
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => const NavbarScreen(),
));
// Navigator.of(context).push(
// MaterialPageRoute(builder: (_){
// return NavbarScreen();
// },
// ),
// );
//print(responseData);
} else {
showToast('gagal login');
}
Navigator.of(context).pop(); //end loading
}
}
}
This is the login logic in login.dart
if (response.statusCode == 200) {
showToast('berhasil login');
Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => const NavbarScreen(),
));
//print(responseData);
} else {
showToast('gagal login');
}
This is main.dart
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Breeze',
theme: ThemeData(
primaryColor: kPrimaryColor,
scaffoldBackgroundColor: Colors.white,
),
//home: DashboardScreen(),
initialRoute: '/',
routes: {
'/': (ctx) => LoginScreen(),
LoginScreen.routeName: (ctx) => LoginScreen(),
NavbarScreen.routeName: (ctx) => NavbarScreen(),
CheckinScreen.routeName: (ctx) => CheckinScreen(),
CheckoutScreen.routeName: (ctx) => CheckoutScreen(),
},
);
}
}
#Damara Jati P Kindly make the following changes Step 1-3
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class LoginScreen extends StatefulWidget {
static const routeName = '/login-screen';
const LoginScreen({Key? key}) : super(key: key);
#override
_LoginScreenState createState() => _LoginScreenState();
}
class _LoginScreenState extends State<LoginScreen> {
TextEditingController txtUsername = new TextEditingController();
TextEditingController txtPassword = new TextEditingController();
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; //provide total height and width
return Scaffold(
body: Background(
child1: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Positioned(
top: 0,
left: 0,
child: Image.asset('assets/images/wedding.png', width: 250),
),
SizedBox(height: size.height * 0.01),
roundedInputField(
hintText: 'Email',
controller: txtUsername,
onChanged: (value) {},
),
PasswordField(
hintText: 'Password',
controller: txtPassword,
onChanged: (value) {},
),
Button(
text: 'LOGIN',
press: () {
// Steps 1
this.doLogin(context);
},
)
],
),
),
),
);
}
void showToast(msg) => Fluttertoast.showToast(msg: msg);
// Steps 2
Future doLogin(BuildContext context) async {
WidgetsBinding.instance.focusManager.primaryFocus?.unfocus();
if (txtUsername.text.isEmpty || txtPassword.text.isEmpty) {
showToast('email/password kosong');
} else {
showDialog(
context: context,
builder: (context) {
return Center(
child: CircularProgressIndicator(),
);
});
final response = await http.post(
Uri.parse('http://10.0.2.2/flutter/api/login'),
body: {'email': txtUsername.text, 'password': txtPassword.text},
headers: {'Accept': 'application/json'});
final responseData = json.decode(response.body);
if (response.statusCode == 200) {
showToast('berhasil login');
// Steps 3
Navigator.push(
context, MaterialPageRoute(builder: (context) => NavbarScreen()));
} else {
showToast('gagal login');
}
}
}
}
try using named route navigator. I show how to route with or without parameters. The generator class contains all the routing definitions in one place
class MyApp extends StatelessWidget{
return MaterialApp(
...
onGenerateRoute: RouteGenerator.handleRoute,
...
}
Navigator.pushNamed(context, RouteGenerator.homePage);
Navigator.pushNamed(
context,
RouteGenerator.page2Page,
arguments: myView)
.then((completion) {
});
class RouteGenerator {
static const String homePage = "/home";
static const String page1Page = "/page1";
static const String page2Page = "/page2";
RouteGenerator._();
static Route<dynamic> handleRoute(RouteSettings routeSettings) {
Widget childWidget;
switch (routeSettings.name) {
case homePage:
{
childWidget = HomePageWidget(title: 'Home');
}
break;
case page1Page:
{
childWidget = Page1Widget();
}
break;
case page2Page:
{
final args = routeSettings.arguments as MyView;
childWidget = Page2Widget(args);
}
break;
default:
throw FormatException("Route Not Found");
}
return MaterialPageRoute(builder: (context) => childWidget);
}
}
Firstly, you are using two different routename for LoginScreen. While this will be the home use
static const routeName = '/';
Now for the method try passing context for safety doLogin(context)
showDialog, push and Fluttertoast.showToast are future methods, provide await before theses.
Future<void> showToast(msg) async => await Fluttertoast.showToast(msg: msg);
showDialog brings another context that is needed to be close to move further. Hopping you are just depending on barrierDismissible: true. else create button or logic to close the dialog.
Future<void> doLogin(BuildContext context) async {
await showDialog(
context: context,
barrierDismissible: true,
builder: (context) {
return Center(
child: Column(
children: [
Center(
child: CircularProgressIndicator(),
),
ElevatedButton(
onPressed: Navigator.of(context).pop,
child: Text("Close the dialog"))
],
),
);
},
);
await showToast('berhasil login');
await Navigator.push(
context,
MaterialPageRoute(
builder: (BuildContext context) => TS(), // place your screen widget
));
}

How to pass a boolean value from one class to another and back?

I am trying to use the Visibility widget to show and hide my page. Here is my logic when at the first page the booean isVisible is true showing the Container widget but as I go to another screen I set the boolean isVisiblevis to false such that my container hides and maintains it state. When I come back from the second screen I want to set the boolean back to true hence showing my container.
First page
class MainScreen extends StatefulWidget {
bool isVisible = true;
MainScreen({this.isVisible});
...
#override
Widget build(BuildContext context) {
body: Container(
//change the margin
margin: EdgeInsets.fromLTRB(0, 0, 0, 300),
child: isVisible ?
Visibility(
maintainAnimation: true,
maintainState: true,
child: (Container(
Text ('first page')
): Container ()
.....
GestureDetector(
onTap: () {
isVisible= false; //set the visibility false
Navigator.push(
//send to search screen
context,
MaterialPageRoute(
builder: (context) => (SecondScreen())));
},
Now on the second page when I pop how do I set the boolean isVisible back to true on first page ?
GestureDetector(
onTap: () {
Navigator.pop(
//send back data
context,
dropOffTextEditingController.text,
);
MainScreen(mapVisible: true,); //doesn't work
},
See what is happening here, when you are setting the isVisible to false you have to use it on the second page means that you have to pass the isVisible data from one page to another. You can refer here:
first.dart
class MainScreen extends StatefulWidget {
bool isVisible = true;
MainScreen({this.isVisible});
}
Navigator.push(context,MaterialPageRoute(builder: (context) => Second(data: isVisible)));
second.dart
class Second extends StatefulWidget {
final String data;
MyPosts({this.data});
}
you can use as widget.data
Refer title and function parameters.
screenone.dart
class ScreenOne extends StatefulWidget {
ScreenOne({Key key = const Key("ScreenOne")}) : super(key: key);
#override
_ScreenOneState createState() => _ScreenOneState();
}
class _ScreenOneState extends State<ScreenOne> {
bool checkScreenOneValue = true;
#override
void initState() {
checkScreenOneValue = true;
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Screen One',
),
),
body: Container(
color: Colors.white,
padding: EdgeInsets.all(15),
child: InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ScreenTwo(
testFunction: testFunction, title: "Screen two")));
},
child: Center(
child: Text(
"Screen Two",
),
),
),
),
);
}
testFunction(bool checkValue) {
checkScreenOneValue = checkValue;
print("****TestFunction $checkScreenOneValue");
}
}
screentwo.dart
class ScreenTwo extends StatefulWidget {
final Function testFunction;
final String title;
const ScreenTwo({required this.testFunction, required this.title});
#override
_ScreenTwoState createState() => _ScreenTwoState();
}
class _ScreenTwoState extends State<ScreenTwo> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
widget.title,
),
),
body: InkWell(
child: Center(child: Text("Back")),
onTap: () {
Navigator.pop(context);
widget.testFunction(false);
},
),
);
}
}

How can i use show case view in flutter?

I use showCaseView package in my app, and want to showcase for one time (just after the first start),
How can I do this only once and not show it on the next launches?
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback(
(_) {
ShowCaseWidget.of(myContext).startShowCase([_one]);
}
);
}
#override
Widget build(BuildContext context) {
return ShowCaseWidget(
// onFinish: ,
builder:
Builder(builder: (context) {
myContext = context;
return Scaffold(
floatingActionButton: Showcase(
key: _one,
title: 'Title',
description: 'Desc',
child: InkWell(
onTap: () {},
child: FloatingActionButton(
onPressed: (){
print("floating");
}
)
),
),
);
}));
}
You can easily do this with the shared_preferences package:
class IsFirstLaunchPage extends StatefulWidget {
static const PREFERENCES_IS_FIRST_LAUNCH_STRING = "PREFERENCES_IS_FIRST_LAUNCH_STRING";
#override
_IsFirstLaunchPageState createState() => _IsFirstLaunchPageState();
}
class _IsFirstLaunchPageState extends State<IsFirstLaunchPage> {
GlobalKey _one = GlobalKey();
BuildContext myContext;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback(
(_) {
_isFirstLaunch().then((result){
if(result)
ShowCaseWidget.of(myContext).startShowCase([_one]);
});
}
);
}
#override
Widget build(BuildContext context) {
return ShowCaseWidget(
// onFinish: ,
builder:
Builder(builder: (context) {
myContext = context;
return Scaffold(
floatingActionButton: Showcase(
key: _one,
title: 'Title',
description: 'Desc',
child: InkWell(
onTap: () {},
child: FloatingActionButton(
onPressed: () {
print("floating");
}
)
),
),
);
}));
}
Future<bool> _isFirstLaunch() async{
final sharedPreferences = await SharedPreferences.getInstance();
bool isFirstLaunch = sharedPreferences.getBool(IsFirstLaunchPage.PREFERENCES_IS_FIRST_LAUNCH_STRING) ?? true;
if(isFirstLaunch)
sharedPreferences.setBool(IsFirstLaunchPage.PREFERENCES_IS_FIRST_LAUNCH_STRING, false);
return isFirstLaunch;
}
}

Can't get data from api

While I am passing value from home page in API page after applying logic how I am not getting data in my result variable. What I am doing wrong?
Here is my home page where I passes the value -
import 'package:flutter/material.dart';
import 'sourceScreen.dart';
import 'models/API.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int value=0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("uTTerNews")),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =1;
API(value: value);
});
},
child:Text('India'),
color: Colors.blue,
),
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =0;
API(value: value);
});
},
child:Text('World'),
color: Colors.blue,
),
],
),
),
);
}
}
Here is my API page where I wanna use that value with some logic which is given below hope u will understand-
import 'model.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class API{
int value;
API({this.value});
Future<List<Source>> fetchNewsSource() async {
final world ='https://newsapi.org/v2/sources?apiKey=';
final india = 'https://newsapi.org/v2/sources?language=en&country=in&apiKey=';
String result;
void logic(){
if(value==1){
result = india;
}
else if(value==0){
result = world;
}
}
final response = await http.get(result);
if (response.statusCode == 200) {
List sources = json.decode(response.body)['sources'];
return sources.map((source) => new Source.formJson(source)).toList();
} else {
throw Exception('Fail to load data');
}
}
}
Here is home page -
import 'package:flutter/material.dart';
import 'sourceScreen.dart';
import 'models/API.dart';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int value=0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("uTTerNews")),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =1;
API(value: value);
});
},
child:Text('India'),
color: Colors.blue,
),
FlatButton(
onPressed: (){
Navigator.push(context, MaterialPageRoute(builder: (context)=>SourceScreen({})));
setState(() {
value =0;
API(value: value);
});
},
child:Text('World'),
color: Colors.blue,
),
],
),
),
);
}
}
Source screen
import 'package:flutter/material.dart';
import 'models/model.dart';
import 'models/card.dart';
import 'article.dart';
import 'models/API.dart';
class SourceScreen extends StatefulWidget {
SourceScreen(Map<int, int> map);
#override
_SourceScreenState createState() => _SourceScreenState();
}
class _SourceScreenState extends State<SourceScreen> {
var list_source;
var refreshKey = GlobalKey<RefreshIndicatorState>();
#override
void initState() {
super.initState();
refreshListSource();
}
Future<Null> refreshListSource() async {
API api = new API();
refreshKey.currentState?.show(atTop: false);
setState(() {
list_source = api.fetchNewsSource();
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: AppBar(
elevation: 1.0,
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
title: Text('uTTerNews'),
),
body: Center(
child: RefreshIndicator(
child: FutureBuilder<List<Source>>(
future: list_source,
builder: (context, snapshot) {
if (snapshot.hasError) {
Text('Error: ${snapshot.error}');
} else if (snapshot.hasData) {
List<Source> sources = snapshot.data;
return new ListView(
children: sources
.map((source) =>
GestureDetector(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) =>
articleScreen(source: source,)));
},
child: card(source),
))
.toList());
}
return CircularProgressIndicator();
},
),
onRefresh: refreshListSource),
),
),
);
}
}
Output:
Try this full code:
void main() => runApp(MaterialApp(home: Home()));
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int value = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("uTTerNews")),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: () async {
value = 1;
List list = await API(value: value).fetchNewsSource();
Navigator.push(context, MaterialPageRoute(builder: (context) => SourceScreen(list)));
},
child: Text('India'),
color: Colors.blue,
),
FlatButton(
onPressed: () async {
value = 0;
List list = await API(value: value).fetchNewsSource();
Navigator.push(context, MaterialPageRoute(builder: (context) => SourceScreen(list)));
},
child: Text('World'),
color: Colors.blue,
),
],
),
),
);
}
}
class API {
int value;
API({#required this.value});
Future<List<dynamic>> fetchNewsSource() async {
final world = 'https://newsapi.org/v2/sources?apiKey=$apiKey';
final india = 'https://newsapi.org/v2/sources?language=en&country=in&apiKey=$apiKey';
String result;
if (value == 1)
result = india;
else if (value == 0) result = world;
final response = await http.get(result);
if (response.statusCode == 200) {
List sources = json.decode(response.body)['sources'];
return sources;
} else {
throw Exception('Fail to load data');
}
}
}
class SourceScreen extends StatefulWidget {
final List list;
SourceScreen(this.list);
#override
_SourceScreenState createState() => _SourceScreenState();
}
class _SourceScreenState extends State<SourceScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Channels")),
body: ListView(
children: widget.list.map((map) => ListTile(title: Text(map["name"]))).toList(),
),
);
}
}