I am currently having an issue while fetching a Provider' value ininitstate`.
I want to set a default value in dropdown in an Appbar and other parts in body. But I got an error saying dependOnInheritedElement() was called before initstate() in flutter.
My full code is below
main.dart
import 'package:test_eoil/model/button_data.dart';
import 'package:test_eoil/model/output_data.dart';
import 'screen/screen.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MultiProvider(providers: [
// ChangeNotifierProvider<ChordData>(create: (context) => ChordData()),
ChangeNotifierProvider<OutputData>(create: (context) => OutputData()),
ChangeNotifierProvider<ButtonData>(create: (context) => ButtonData())
],
child: MaterialApp(
home: Screen(),
),
);
}
}
screen.dart in screen folder
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:test_eoil/model/button_data.dart';
import 'package:test_eoil/model/output_data.dart';
class Screen extends StatefulWidget {
#override
_ScreenState createState() => _ScreenState();
}
class _ScreenState extends State<Screen> {
Widget dropdownWidget() {
return DropdownButton<Button>(
items: Provider.of<ButtonData>(context).buttons.map((Button value) {
return new DropdownMenuItem<Button>(
value: value,
child: new Text(value.type.toString()),
);
}).toList(),
onChanged: (Button newValue) {
Provider.of<ButtonData>(context).setSelectedItem(newValue);
},
value: Provider.of<ButtonData>(context).selectedButton,
);
}
#override
void initState() {
Provider.of<ButtonData>(context).selectedButton = Provider.of<ButtonData>(context).buttons.first;
super.initState();
}
#override
Widget build(BuildContext context) {
return Consumer<OutputData>(
builder: (context, outputData, child) => Scaffold(
appBar: AppBar(
title: Text("${Provider.of<ButtonData>(context).selectedButton}"), // new Text(widget.title), // "${Provider.of<ButtonData>(context).selectedButton.key}"
actions: <Widget>[
dropdownWidget(),
],
),
body: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
alignment: Alignment.centerRight,
padding: new EdgeInsets.symmetric(
vertical: 24.0, horizontal: 12.0),
child: outputData.outputs[0].output3.length > 2
? Text(
'${outputData.outputs[0].output3.substring(1, outputData.outputs[0].output3.length-1)}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
))
: Text('${outputData.outputs[0].output3}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
)),
),
Container(
alignment: Alignment.centerRight,
padding: new EdgeInsets.symmetric(
vertical: 24.0, horizontal: 12.0),
child: outputData.outputs[0].output2.length > 2
? Text(
'${outputData.outputs[0].output2.substring(1, outputData.outputs[0].output2.length-1)}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
))
: Text('${outputData.outputs[0].output2}',
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
)),
),
Container(
alignment: Alignment.centerRight,
padding: new EdgeInsets.symmetric(
vertical: 24.0, horizontal: 12.0),
child: Text('${outputData.outputs[0].output1}', // outputData.outputs[0].output1
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.bold,
)),
),
],
),
Expanded(
child: new Divider(),
),
Column(children: [
Row(children: [
buildButton("CLEAR"),
buildButton(""),
buildButton("PLAY"),
// buildButton("/")
]),
])
],
)));
}
Widget buildButton(String buttonText) {
return new Expanded(
child: new OutlineButton(
padding: new EdgeInsets.all(30.0),
child: new Text(
buttonText,
style: TextStyle(fontSize: 20.0),
),
onPressed: () => print("test"),
),
);
}
}
button_data.dart in model folder
import 'package:flutter/foundation.dart';
//import 'dart:collection';
class Button {
final int id;
final String type;
final String numberone;
final String numbertwo;
final String numberthree;
Button({this.id, this.type, this.numberone, this.numbertwo, this.numberthree});
}
class ButtonData extends ChangeNotifier {
List<Button> _buttons = [
Button(
type: "A",
numberone: "1",
numbertwo: "2",
numberthree: "3",
),
Button(
type: "B",
numberone: "A",
numbertwo: "B",
numberthree: "C",
),
];
List<Button> get buttons => _buttons;
Button _selectedButton;
Button get selectedButton => _selectedButton;
set selectedButton(Button button) {
_selectedButton = button;
notifyListeners();
}
void setSelectedItem(Button s) {
_selectedButton = s;
notifyListeners();
}
Button getKey(String value) {
return _buttons
.where((button) => button.type == value).first;
}
String getNumberOne(String value) {
return _buttons
.where((button) => button.type == value)
.map((button) => (button.numberone))
.toString();
}
String getNumberTwo(String value) {
return _buttons
.where((button) => button.type == value)
.map((button) => (button.numbertwo))
.toString();
}
String getNumberThree(String value) {
return _buttons
.where((button) => button.type == value)
.map((button) => (button.numberthree))
.toString();
}
}
output_data.dart in model folder
import 'package:flutter/foundation.dart';
class Output {
final int id;
String output1;
String output2;
String output3;
Output({this.id, this.output1, this.output2, this.output3});
}
class OutputData extends ChangeNotifier {
List<Output> _outputs = [
Output(output1: 'Hello', output2: 'Hi', output3: 'Nice'),
Output(output1: 'Haha', output2: 'Bye', output3: 'Sad'),
];
List<Output> get outputs {
return _outputs;
}
}
To be honest, I want to make it work without initstate() if possible(I heard that provider pattern doesn't need stful)
The reason I come up with an initstate() is this is the only solution (as much as I know) to set the default value in provider.
Hope you guys help me!
Issue is solved by adding Button_data constructor in button_data.dart.
ButtonData () {
_selectedButton = _buttons.first;
}
I also mentioned in my previous answer that Provider.of(context) is supposed to be used inside the widget tree, and anything that is outside of the build() method, is not in the widget tree. But if you still want to use it, then you need to set the listen parameter to false.
Like so:
#override
void initState() {
Provider.of<ButtonData>(context, listen: false).selectedButton = Provider.of<ButtonData>(context, listen: false).buttons.first;
super.initState();
}
But as you mentioned in your question, you don't want to use initState to set the default value. In every programming language, when you declare a variable with a value, that value becomes it's initial / default value, and you can change it later.
Instead of using initState, you can edit the following in your ButtonData class.
//Remove this.
List<Button> get buttons => _buttons;
Button _selectedButton;
Button get selectedButton => _selectedButton;
//Instead, Use this.
List<Button> get buttons => _buttons;
Button _selectedButton = _buttons.first;
Button get selectedButton => _selectedButton;
//This will declare the `selectedButton` variable with a default value.
//Happy coding! :)
Another solution when "dependOnInheritedElement() was called before initState()" could also be to access BuildContext safely in the initState method. It could be done by the following:
WidgetsBinding.instance.addPostFrameCallback((_) async {
// your code goes here
});
WidgetsBinding.instance.addPostFrameCallback((_) {
enter code here
});
This worked for me ->
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) async {
final authViewModel = Provider.of<AuthViewModel>(context, listen: false);
authViewModel.getToken();
});
}
Related
I'm trying to create a pageview that I can load a widget into that is defined in another file. This works fine, except when I try to add a callback, I get the following error:
FlutterError (setState() or markNeedsBuild() called during build.
This error is triggered when the email entered is considered to be valid (that is, when the code in the email_entry.dart calls the callback function that was passed from the account_onboarding.dart file.) I haven't been able to determine why this is happening, and no tutorials on this subject seem to exist. I am still pretty new to Dart/Flutter, so I'm hoping someone can point out what's happening (and a fix) here.
Here is my code:
-Parent widget, account_onboarding.dart
import 'package:flutter/material.dart';
import 'package:page_view_indicators/page_view_indicators.dart';
import 'package:animated_title_screen/screens/email_entry.dart';
class AccountOnboarding extends StatefulWidget {
const AccountOnboarding({Key? key}) : super(key: key);
#override
State<AccountOnboarding> createState() => _AccountOnboardingState();
}
class _AccountOnboardingState extends State<AccountOnboarding> {
final _pController = PageController(initialPage: 0);
final _currentPageNotifier = ValueNotifier<int>(0);
final List<Widget> _pages = [];
bool validEmail = false; //Callback should set this variable
#override
void initState() {
super.initState();
_pages.add( //Add the EmailEntry widget to the list
EmailEntry(emailIsValid: (p0) {
setState(() {
validEmail = p0;
});
},),
);
_pages.add(
Container(
color: Colors.blue,
child: Text("Pg2"),
),
);
_pages.add(
Container(
color: Colors.green,
child: Text("Pg3"),
),
);
}
#override
void dispose() {
_pController.dispose();
_currentPageNotifier.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Create Account",
style: Theme.of(context).textTheme.headline5,
),
centerTitle: true,
actions: [
IconButton(
icon: const Icon(Icons.close),
onPressed: () => Navigator.pop(context),
),
],
),
body: Stack(
fit: StackFit.expand,
children: [
Column(
children: [
Row(
children: [
Text(
"Step ${_currentPageNotifier.value + 1} of ${_pages.length}",
),
CirclePageIndicator(
dotColor: const Color(0xFF323232),
selectedDotColor: const Color(0xFFE4231F),
size: 10,
selectedSize: 10,
currentPageNotifier: _currentPageNotifier,
itemCount: _pages.length,
),
],
),
PageView(
controller: _pController,
onPageChanged: (index) {
setState(() {
_currentPageNotifier.value = index;
});
},
children: [
for (Widget p in _pages) p, //Display all pages in _pages[]
],
),
ElevatedButton(
child: const Text("Continue"),
onPressed: () => print("Pressed 2"),
style: ElevatedButton.styleFrom(
primary: validEmail ? const Color(0xFFE1251B) : Colors.black,
textStyle: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 15,
),
),
),
],
),
],
),
);
}
}
Here is the email_entry.dart code:
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
class EmailEntry extends StatefulWidget {
final Function(bool) emailIsValid; //Function required in constructor
const EmailEntry({Key? key, required this.emailIsValid}) : super(key: key);
#override
State<EmailEntry> createState() => _EmailEntryState();
}
class _EmailEntryState extends State<EmailEntry> {
final _emailController = TextEditingController();
FocusNode _emailFocus = FocusNode();
#override
void initState() {
super.initState();
_emailController.addListener(() => setState(() {}));
_emailFocus.addListener(() {
print("Focus email");
});
}
#override
void dispose() {
_emailController.dispose();
super.dispose();
}
bool validateEmail(String email) {
bool valid = RegExp(
r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,253}[a-zA-Z0-9])?)*$")
.hasMatch(email);
if (valid) {
widget.emailIsValid(true); //Call the callback function
}
return valid;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Column(
children: [
Text(
"YOUR EMAIL",
style: Theme.of(context).textTheme.headline2,
),
Text(
"Please use an email address that you would like to make your login.",
style: Theme.of(context).textTheme.bodyText2,
textAlign: TextAlign.center,
),
Container(
child: Text(
"Email Address",
),
),
TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
focusNode: _emailFocus,
suffixIcon: getTextFieldSuffix(emailController, _emailFocus), //OFFENDING CODE
),
],
),
],
),
);
}
//THIS FUNCTION CAUSED THE ISSUE. It is code I got from a youtube //tutorial. Probably should have guessed.
Widget getTextFieldSuffix(TextEditingController controller, FocusNode node) {
if (controller.text.isNotEmpty && node.hasFocus) {
return IconButton(
color: Colors.grey.withAlpha(150),
onPressed: () => controller.clear(),
icon: const Icon(Icons.close));
} else if (controller.text.isNotEmpty && !node.hasFocus) {
return const Icon(
Icons.check,
color: Colors.green,
);
}
return Container(
width: 0,
);
}
}
in initState,you need to call addPostFrameCallback.
like this...
#override
void initState() {
super.initState();
///Add This Line
WidgetsBinding.instance?.addPostFrameCallback((timeStamp) {
///All of your code
});
}
I found out that there is some code in my production version that calls a redraw every time the user enters a letter into the textfield for the email address. This was causing a problem because the screen was already being redrawn, and I was calling setState to redraw it again. I will edit the code shown above to include the offending code.
I'm trying to pass the String parameter to the widgets but unfortunately it's not working and i don't know how is that happening because i have worked on the same parameter in another widget and it has worked :'(.
Here is my code:
MainPage.dart
//---------------------------------------------------------
//Assigned String from here and it works with the widgets except: MainHydrationProgressPage
//---------------------------------------------------------
late final String? tanksID = ModalRoute.of(context)?.settings.arguments as String?;
late final _pages = <Widget>[
MainTankHydrationPoolPage(tankID: tanksID,),
MainHydrationProgressPage(tanksID: tanksID,),
SummaryPage(tanksID: tanksID),
];
MainHydrationProgressPage.dart
import 'package:flutter/material.dart';
import 'package:smart_tank1/main_tank_detail_ui/hydration_progress/progress_view.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter_locales/flutter_locales.dart';
class MainHydrationProgressPage extends StatefulWidget {
//-----------------
//Here is the String that i want to work on
//-----------------
final String? tanksID;
MainHydrationProgressPage({Key? key, required this.tanksID});
static const routeName = 'progress-screen';
#override
_MainHydrationProgressPageState createState() => _MainHydrationProgressPageState();
}
class _MainHydrationProgressPageState extends State<MainHydrationProgressPage> {
bool onAndOff = false;
late final dbRef = FirebaseDatabase.instance;
//final fStore = FirebaseFirestore.instance;
#override
void initState(){
dbRef;
//fStore;
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Padding(
padding: const EdgeInsets.only(bottom: 136, top: 32.0),
child: Column(
children: [
SizedBox(width: double.infinity),
LocaleText(
"waterPercentage",
style: Theme.of(context).textTheme.headline4,
),
Expanded(
//-------------------------------------------------------------------------------------------
//Trying to assign tanksID here but it's not working it keeps showing the error line under it
//-------------------------------------------------------------------------------------------
child: ProgressView(ID: tanksID),
),
SizedBox(height: 10,),
Padding(
padding: const EdgeInsets.only(left: 20.0, right: 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
LocaleText('pump', style: TextStyle(fontSize: 20),),
buildSwitch(),
],
),
),
],
),
),
);
}
Widget buildSwitch() => Transform.scale(
scale: 1.5,
child: Switch.adaptive(
activeColor: Colors.blueAccent,
activeTrackColor: Colors.blue.withOpacity(0.4),
inactiveThumbColor: Colors.white,
inactiveTrackColor: Colors.grey,
splashRadius: 50,
value: onAndOff,
onChanged: (value){
final user = FirebaseAuth.instance.currentUser;
setState(() {
onAndOff = value;
if (value) {
//--------------
//1. Firestore
//--------------
// fStore.collection('esp').doc(user.uid).update({
// 'pump': 'on',
// });
//-----------------
//2. Realtime database
//-----------------
dbRef.ref().child('users'). child(user!.uid).child('pump').set('on').asStream();
}else {
//--------------
//1. Firestore
//--------------
// fStore.collection('esp').doc(user.uid).update({
// 'pump': 'off',
// });
//-----------------
//2. Realtime database
//-----------------
dbRef.ref().child('users').child(user!.uid).child('pump').set('off').asStream();
}
},
);
}
),
);
}
Here is what it tells me: Undefined name 'tanksID'.
Try correcting the name to one that is defined, or defining the name.
Anyone faced this problem before? and how can it be solved!
I did flutter clean and flutter get packages then restarted vscode but it didn't work! :'(
please help
It worked with you before because maybe you were using a stateless widget or the variable defined in the state itself, but in this case you have a stateful widget and the variable is defined in the stateful widget not in the state itself, so you have to call it like: widget.tanksID
I'm trying to make a weather app with Flutter. But for some reason, the build() method runs before the initState() method finishes. The thing is, all the state variables are initialized using the setState() method inside the initState(), whose variables are to be used in build() method. I guess the problem is that Flutter is trying to access those state variables before the setState() method, which keeps throwing me the error: A non-null String must be provided to a Text widget. I know these codes are too long to read. But I'd appreciate it if you could help me with this.
import 'package:flutter/material.dart';
import "package:climat/screens/LoadingScreen.dart";
import "package:climat/screens/MainScreen.dart";
import "package:climat/screens/SearchScreen.dart";
void main() {
runApp(
MaterialApp(
theme: ThemeData(
fontFamily: "Open Sans",
),
title: "Climat",
initialRoute: "/",
onGenerateRoute: (RouteSettings routeSettings) {
dynamic routes = <String, WidgetBuilder>{
"/": (context) => LoadingScreen(),
"/index": (context) => MainScreen(),
"/search": (context) => SearchScreen(),
};
WidgetBuilder builder = routes[routeSettings.name];
return MaterialPageRoute(builder: (context) => builder(context));
},
),
);
}
import "package:flutter/material.dart";
import "package:flutter_spinkit/flutter_spinkit.dart";
import "package:climat/services/GeolocatorHelper.dart";
import "package:climat/services/NetworkHelper.dart";
import "package:climat/utilities/constants.dart";
class LoadingScreen extends StatefulWidget {
#override
_LoadingScreenState createState() => _LoadingScreenState();
}
class _LoadingScreenState extends State<LoadingScreen> {
Future<void> getWeatherData() async {
Map<String, double> coordinates = await GeolocatorHelper().getGeoData();
final NetworkHelper networkHelper = NetworkHelper(
uri:
"$endPoint&lat=${coordinates["latitude"]}&lon=${coordinates["longitude"]}");
final dynamic data = await networkHelper.getData();
return await Navigator.pushNamed(context, "/index", arguments: data);
}
#override
void initState() {
this.getWeatherData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Climat"),
),
body: SafeArea(
child: Center(
child: SpinKitRing(
color: Colors.redAccent,
),
),
),
);
}
}
import "package:flutter/material.dart";
import "package:climat/services/WeatherHelper.dart";
import "package:climat/services/NetworkHelper.dart";
import "package:climat/utilities/constants.dart";
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
Color backgroundColor;
String cityName;
int temperature;
String status;
String image;
int minTemperature;
int maxTemperature;
int humidity;
Future<void> updateUI({String userInput = null}) async {
dynamic weatherData;
if (userInput == null) {
weatherData = ModalRoute.of(context).settings.arguments;
} else {
final NetworkHelper networkHelper =
NetworkHelper(uri: "$endPoint&q=$userInput");
weatherData = await networkHelper.getData();
}
final int weatherCode = weatherData["weather"][0]["id"];
final WeatherHelper weatherHelper = WeatherHelper(
weatherCode: weatherCode,
);
setState(() {
this.backgroundColor = weatherHelper.getBackgroundColor();
this.cityName = weatherData["name"];
this.temperature = weatherData["main"]["temp"].toInt();
this.status = weatherHelper.getWeatherStatus();
this.minTemperature = weatherData["main"]["temp_min"].toInt();
this.maxTemperature = weatherData["main"]["temp_max"].toInt();
this.humidity = weatherData["main"]["humidity"];
this.image = weatherHelper.getWeatherImage();
});
}
#override
void initState() {
this.updateUI();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: this.backgroundColor,
appBar: AppBar(
title: Text("Climat"),
),
body: SafeArea(
child: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
this.cityName,
style: TextStyle(
fontSize: 24.0,
color: Colors.white,
),
),
SizedBox(
height: 30.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
"./assets/images/${this.image}",
scale: 4.0,
),
SizedBox(
width: 30.0,
),
Text(
"${this.temperature}°C",
style: TextStyle(
fontSize: 96.0,
color: Colors.white,
),
),
],
),
SizedBox(
height: 30.0,
),
Text(
this.status.toUpperCase(),
style: TextStyle(
fontSize: 24.0,
color: Colors.white,
),
),
SizedBox(
height: 10.0,
),
Text(
"MIN / MAX : ${this.minTemperature.toString()} / ${this.maxTemperature.toString()}",
style: TextStyle(
fontSize: 24.0,
color: Colors.white,
),
),
SizedBox(
height: 10.0,
),
Text(
"HUMIDITY : ${this.humidity}%",
style: TextStyle(
fontSize: 24.0,
color: Colors.white,
),
),
SizedBox(
height: 30.0,
),
ElevatedButton(
onPressed: () async {
dynamic userInput =
await Navigator.pushNamed(context, "/search");
this.updateUI(
userInput: userInput.toString(),
);
},
style: ElevatedButton.styleFrom(
padding: EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 16.0,
),
),
child: Text(
"Search by city name",
style: TextStyle(
fontSize: 20.0,
),
),
),
],
),
),
),
);
}
}
if you want to use Future function in initState and want it run once and complete before build, please consider to use WidgetsBinding.instance.addPostFrameCallback, like
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await this.getWeatherData();
setState(() { });
});
}
and
#override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((_) async {
await this.updateUI();
setState(() { });
});
}
setState should be used for rebuild the widget
I'm trying to use provider in my flutter app to allow the user to change the font size for some widgets.
I'm following the method described in github.com/flutter/samples/blob/master/provider_counter/lib/main.dart but the font size isn't changing.
I have a UI widget which shows plus and minus buttons:
import "package:flutter/material.dart";
import './size_controller.dart';
import 'package:provider/provider.dart';
class TypeSize extends StatelessWidget {
final _standardSize = 20.0;
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20.0),
child: Row(
children: <Widget>[
Text(
"Change type size: ",
style: TextStyle(fontSize: _standardSize),
),
ButtonTheme(
minWidth: 50,
child: RaisedButton(
onPressed: () {
if (_standardSize < 23.0) {
Provider.of<FontSizeController>(context, listen: false).increment(_standardSize);
}
},
child: Text(
"+", style: TextStyle(
color: Colors.white,
fontSize: 30),
),
color: Colors.green,
),
),
ButtonTheme(
minWidth: 50,
child: RaisedButton(
onPressed: () {
if (_standardSize > 20.0) {
Provider.of<FontSizeController>(context, listen: false).decrement(_standardSize);
}
},
child: Text(
"-", style: TextStyle(
color: Colors.white,
fontSize: 30,
),
),
color: Colors.green,
),
),
],
),
);
}
}
FontSizeController looks like this:
import 'package:flutter/material.dart';
class FontSizeController with ChangeNotifier {
double value = 20.0;
void increment(value) {
value ++;
notifyListeners();
}
void decrement(value) {
value --;
notifyListeners();
}
}
and finally the widget that I want to change looks like this:
import 'package:flutter/material.dart';
// import 'package:wfa_ambo_bloc/main.dart';
import 'package:provider/provider.dart';
import '../controllers/size_controller.dart';
class Comfort extends StatefulWidget {
#override
_ComfortState createState() => _ComfortState();
}
class _ComfortState extends State<Comfort> {
int _comfortSliderValue = 3;
// double _standardSize = 20;
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 40),
child: Column(
children: <Widget>[
Align(
alignment: Alignment.centerLeft,
child: ChangeNotifierProvider(
create: (context) => FontSizeController(),
child: Container(
padding: EdgeInsets.all(20.0),
child: Consumer<FontSizeController>(
builder: (
context,
sizeController,
child) => Text(
"How comfortable was your journey?",
textAlign: TextAlign.left,
style: TextStyle(
fontWeight: FontWeight.w400,
fontFamily: "Roboto",
letterSpacing: 0.5,
fontSize: sizeController.value,
),
),
),
),
),
),
... etc
Nothing is happening when the buttons are clicked. Can anybody help please?
The example that I'm trying to adapt is all contained within the main() but I've separated out my widgets to try and make everything cleaner - is that what is making the difference?
No need to use a variable in your widget (remove _standardSize).
Just keep the value in your ChangeNotifier and use it directly (through a getter) :
import 'package:flutter/material.dart';
class FontSizeController with ChangeNotifier {
double _value = 20.0;
int get value => _value;
void increment() {
_value++;
notifyListeners();
}
void decrement() {
_value--;
notifyListeners();
}
}
Then on plus and minus buttons, simply increment or decrement value from your ChangeNotifier :
// on plus button pressed
Provider.of<FontSizeController>(context, listen: false).increment();
// on minus button pressed
Provider.of<FontSizeController>(context, listen: false).decrement();
Finally in the widget where you want your text to be sized :
fontSize: Provider.of<FontSizeController>(context, listen: true).value
final String url = 'https://onobang.com/flutter';
// here is my backend code decrlareData.dart
class UserDetails {
final String id;
final String firstName, proVinsi, link, profileUrl, ket, kab;
UserDetails({
this.id,
this.firstName,
this.proVinsi,
this.link,
this.profileUrl,
this.ket,
this.kab,
});
factory UserDetails.fromJson(Map<String, dynamic> json) {
return new UserDetails(
id: json['id'],
firstName: json['name'],
proVinsi: json['provinsi'],
profileUrl:
"https://onobang.com/daiku/ajaximageupload/manajemen/uploads/" +
json['file_name'],
ket: json['ket'],
link: json['link'],
kab: json['kabupaten'],
);
}
}
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:url_launcher/url_launcher.dart';
import 'declareData.dart';
import 'detail.dart';
// here is my fetch data and view with search result,
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage>
with SingleTickerProviderStateMixin {
List<UserDetails> _searchResult = [];
List<UserDetails> _userDetails = [];
TextEditingController controller = new TextEditingController();
// Get json result and convert it to model. Then add
Future<Null> getUserDetails() async {
final response = await http.get(url);
final responseJson = json.decode(response.body);
setState(() {
for (Map user in responseJson) {
_userDetails.add(UserDetails.fromJson(user));
}
});
}
#override
void initState() {
super.initState();
getUserDetails();
}
Widget _buildUsersList() {
return new ListView.builder(
itemCount: _userDetails.length,
itemBuilder: (context, index) {
return new Card(
child: new ListTile(
leading: new CircleAvatar(
backgroundImage: new NetworkImage(
_userDetails[index].profileUrl,
),
),
title: new Text(' Nama : ' +
_userDetails[index].firstName +
' ' +
_userDetails[index].kab),
subtitle: new Text('Provinsi : ' + _userDetails[index].proVinsi ),
isThreeLine: true,
trailing: (IconButton(
icon: Icon(Icons.expand_more),
)
),
onTap: () {
var route = new MaterialPageRoute(
builder: (BuildContext context) =>
new SecondScreen(value: _userDetails[index]),
);
Navigator.of(context).push(route);
},
),
margin: const EdgeInsets.all(0.0),
);
},
);
}
//Widget futureBuilder() {
//future:
Widget _buildSearchResults() {
return new ListView.builder(
itemCount: _searchResult.length,
itemBuilder: (context, i) {
return new Card(
child: new ListTile(
leading: new CircleAvatar(
backgroundImage: new NetworkImage(
_searchResult[i].profileUrl,
),
),
title: new Text(_searchResult[i].firstName +
' || Kab ' +
_searchResult[i].kab),
subtitle: new Text('Prov : ' + _searchResult[i].proVinsi),
onTap: () {
var route = new MaterialPageRoute(
builder: (BuildContext context) =>
new SecondScreen(value: _searchResult[i]),
);
Navigator.of(context).push(route);
},
),
margin: const EdgeInsets.all(0.0),
);
},
);
}
Widget _buildSearchBox() {
return new Padding(
padding: const EdgeInsets.all(8.0),
child: new Card(
child: new ListTile(
leading: new Icon(Icons.search),
title: new TextField(
controller: controller,
decoration: new InputDecoration(
hintText: 'Search', border: InputBorder.none),
onChanged: onSearchTextChanged,
),
trailing: new IconButton(
icon: new Icon(Icons.cancel),
onPressed: () {
controller.clear();
onSearchTextChanged('');
},
),
),
),
);
}
Widget _buildBody() {
return new Column(
children: <Widget>[
FlatButton.icon(
color: Colors.white,
icon: Icon(FontAwesomeIcons.whatsapp), //`Icon` to display
label: Text('089xxxx465'), //`Text` to display
onPressed: () {
launch('https://www.instagram.com/?hl=id');
},
),
new Container(
color: Theme.of(context).primaryColor, child: _buildSearchBox()),
new Expanded(
child: _searchResult.length != 0 || controller.text.isNotEmpty
? _buildSearchResults()
: _buildUsersList()),
],
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: _buildBody(),
// body: new RefreshIndicator(child: null, onRefresh: null),
resizeToAvoidBottomPadding: true,
);
}
onSearchTextChanged(String text) async {
_searchResult.clear();
if (text.isEmpty) {
setState(() {});
return;
}
_userDetails.forEach((userDetail) {
if (userDetail.firstName.toUpperCase().contains(text.toUpperCase()) ||
userDetail.proVinsi.toUpperCase().contains(text.toUpperCase())||
userDetail.kab.toUpperCase().contains(text.toUpperCase()))
_searchResult.add(userDetail);
});
setState(() {});
}
}
import 'package:flutter/material.dart';
import 'declareData.dart';
import 'package:flutube/flutube.dart';
import 'package:flutter/services.dart';
// here is the single post
class SecondScreen extends StatefulWidget {
final UserDetails value;
SecondScreen({Key key, this.value}) : super(key: key);
#override
_SecondScreenState createState() => _SecondScreenState();
}
//detail start
class _SecondScreenState extends State<SecondScreen> {
int currentPos;
String stateText;
#override
void initState() {
currentPos = 0;
stateText = "Video not started";
super.initState();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(title: new Text('Profil Ustad')),
body: new Container(
child: new Center(
child: Column(
children: <Widget>[
Padding(
child: new Text(
'${widget.value.firstName}',
style: new TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20.0,
),
textAlign: TextAlign.center,
),
padding: EdgeInsets.only(top: 20.0),
),
/* Padding(
//`widget` is the current configuration. A State object's configuration
//is the corresponding StatefulWidget instance.
child: Image.network('${widget.value.profileUrl}'),
padding: EdgeInsets.all(12.0),
),*/
Padding(
child: new Text(
'Nama : ${widget.value.firstName}',
style: new TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.left,
),
padding: EdgeInsets.all(10.0),
),
Padding(
child: new Text(
'PROVINSI : ${widget.value.proVinsi}',
style: new TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.left,
),
padding: EdgeInsets.all(0.0),
),
Padding(
child: new Text(
'Ket : ${widget.value.ket}',
style: new TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.justify,
),
padding: EdgeInsets.all(10.0),
),
],
),
),
),
);
}
}
i'm trying to make a specific search in flutter, the case is, i'd like user can choose option that was, province and district , than after user select the specific location they want, user click a button than we fetch data from mysql json.so i wish i can change value in url variable than i can get specific data from my json.
final String url = 'https://onobang.com/flutter/index.php?'+'province='
import 'package:flutter/material.dart';
void main() {
runApp(new MaterialApp(
title: "Para Dai",
home: new DropDown(),
));
}
import 'package:flutter/material.dart';
class DropDown extends StatefulWidget {
DropDown() : super();
final String title = "DropDown Demo";
#override
DropDownState createState() => DropDownState();
}
class Provinces {
int id;
String name;
Provinces(this.id, this.name);
static List<Provinces> getCompanies() {
return <Provinces>[
Provinces(1, 'Central Java'),
Provinces(2, 'East kalimantan'),
Provinces(3, 'East java'),
Provinces(4, 'Bali'),
Provinces(5, 'Borneo'),
];
}
}
class DropDownState extends State<DropDown> {
//
List<Provinces> _provinceses = Provinces.getCompanies();
List<DropdownMenuItem<Provinces>> _dropdownMenuItems;
Provinces _selectedProvinces;
#override
void initState() {
_dropdownMenuItems = buildDropdownMenuItems(_provinceses);
_selectedProvinces = _dropdownMenuItems[0].value;
super.initState();
}
// here the url i wish can dynamicly edit by user input
final String url = 'https://onobang.com/flutter/index.php?'+'province='_selectedProvinsi.name+'district'some.district;
List<DropdownMenuItem<Provinces>> buildDropdownMenuItems(List provinceses) {
List<DropdownMenuItem<Provinces>> items = List();
for (Provinces province in provinceses) {
items.add(
DropdownMenuItem(
value: province,
child: Text(province.name),
),
);
}
return items;
}
onChangeDropdownItem(Provinces selectedProvinces) {
setState(() {
_selectedProvinces = selectedProvinces;
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
appBar: new AppBar(
title: new Text("DropDown Button Example"),
),
body: new Container(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Select a province"),
SizedBox(
height: 20.0,
),
DropdownButton(
value: _selectedProvinces,
items: _dropdownMenuItems,
onChanged: onChangeDropdownItem,
),
SizedBox(
height: 20.0,
),
Text('Selected: ${_selectedProvinces.name}'),
],
),
),
),
),
);
}
}
Demo
Do you need something like this?
You can build it locally using this repo Github.
What to Do
Make District class that similiar to Province
Initiate Dropdown for District
Set initial value for selectedDistrict
Lastly, modify URL before calling setState
Full Code
import 'package:flutter/material.dart';
class DropDown extends StatefulWidget {
DropDown() : super();
final String title = "DropDown Demo";
#override
DropDownState createState() => DropDownState();
}
class Province {
int id;
String name;
Province(this.id, this.name);
static List<Province> getProvinceList() {
return <Province>[
Province(1, 'Central Java'),
Province(2, 'East kalimantan'),
Province(3, 'East java'),
Province(4, 'Bali'),
Province(5, 'Borneo'),
];
}
}
// ADD THIS
class District {
int id;
String name;
District(this.id, this.name);
static List<District> getDistrictList() {
return <District>[
District(1, 'Demak'),
District(2, 'Solo'),
District(3, 'Sidoarjo'),
District(4, 'Bandung'),
];
}
}
class DropDownState extends State<DropDown> {
String finalUrl = '';
List<Province> _provinces = Province.getProvinceList();
List<DropdownMenuItem<Province>> _dropdownMenuItems;
Province _selectedProvince;
// ADD THIS
List<District> _disctricts = District.getDistrictList();
List<DropdownMenuItem<District>> _dropdownMenuDistricts;
District _selectedDistrict;
#override
void initState() {
_dropdownMenuItems = buildDropdownMenuItems(_provinces);
_dropdownMenuDistricts = buildDropdownDistricts(_disctricts); // Add this
_selectedProvince = _dropdownMenuItems[0].value;
_selectedDistrict = _dropdownMenuDistricts[0].value; // Add this
super.initState();
}
List<DropdownMenuItem<Province>> buildDropdownMenuItems(List provinceses) {
List<DropdownMenuItem<Province>> items = List();
for (var province in provinceses) {
items.add(
DropdownMenuItem(
value: province,
child: Text(province.name),
),
);
}
return items;
}
// ADD THIS
List<DropdownMenuItem<District>> buildDropdownDistricts(List<District> districts) {
List<DropdownMenuItem<District>> items = List();
for (var district in districts) {
items.add(
DropdownMenuItem(
value: district,
child: Text(district.name),
),
);
}
return items;
}
onChangeDropdownItem(Province newProvince) {
// Add this
final String url = 'https://onobang.com/flutter/index.php?province=${newProvince.name}&district=${_selectedDistrict.name}';
setState(() {
_selectedProvince = newProvince;
finalUrl = url; // Add this
});
}
onChangeDistrict(District newDistrict) {
// Add this
final String url = 'https://onobang.com/flutter/index.php?province=${_selectedProvince.name}&district=${newDistrict.name}';
setState(() {
_selectedDistrict = newDistrict;
finalUrl = url; // Add this
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
debugShowCheckedModeBanner: false,
home: new Scaffold(
appBar: new AppBar(
title: new Text("DropDown Button Example"),
),
body: new Container(
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Select a province"),
SizedBox(
height: 20.0,
),
DropdownButton(
value: _selectedProvince,
items: _dropdownMenuItems,
onChanged: onChangeDropdownItem,
),
SizedBox(
height: 20.0,
),
Text('Selected: ${_selectedProvince.name}'),
SizedBox(
height: 20.0,
),
Text("Select a district"),
SizedBox(
height: 20.0,
),
// Add this
DropdownButton(
value: _selectedDistrict,
items: _dropdownMenuDistricts,
onChanged: onChangeDistrict,
),
SizedBox(
height: 20.0,
),
Text('Selected: ${_selectedDistrict.name}'),
SizedBox(
height: 30.0,
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text('$finalUrl'),
),
],
),
),
),
),
);
}
}