Flutter Inherited Widget - Missing some listener - flutter

I'm trying to get the following to work. Changes to the app model state are not picked up via the InheritedWidget 'AppStateProvider'. I've manage to get this working with sinks/streams but was hoping to established a simpler structure.
This is just a test application to switch between various app modes.
What's missing?
import 'package:flutter/material.dart';
void main() {
runApp(AppStateProvider(
child: RootPage(),
appState: new AppState(),
));
}
enum AppMode { introduction, login, home }
class AppState {
AppMode appMode;
AppState({
this.appMode = AppMode.introduction,
});
}
class AppStateProvider extends InheritedWidget {
final AppState appState;
AppStateProvider({Key key, Widget child, this.appState})
: super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
static AppStateProvider of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(AppStateProvider)
as AppStateProvider);
}
}
class RootPage extends StatelessWidget {
AppMode _mode;
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Inherited Widget Test',
theme: new ThemeData(
primarySwatch: Colors.blueGrey,
),
home: _body(context),
);
}
Widget _body(BuildContext context) {
final provider = AppStateProvider.of(context); //Registers as a listener
final state = provider.appState;
_mode = state.appMode;
return new Stack(
children: <Widget>[
new Offstage(
offstage: _mode != AppMode.introduction,
child: new MaterialApp(
home: ColorsListPage(
color: Colors.red,
targetAppMode: AppMode.login,
title: "Intro",
),
),
),
new Offstage(
offstage: _mode != AppMode.login,
child: new MaterialApp(
home: ColorsListPage(
color: Colors.blue,
targetAppMode: AppMode.home,
title: "Login",
),
),
),
new Offstage(
offstage: _mode != AppMode.home,
child: new MaterialApp(
home: ColorsListPage(
color: Colors.green,
targetAppMode: AppMode.introduction,
title: "Home",
),
),
),
],
);
}
}
class ColorDetailPage extends StatefulWidget {
final String title;
final MaterialColor color;
final int materialIndex;
final AppMode targetAppMode;
ColorDetailPage(
{this.color, this.title, this.targetAppMode, this.materialIndex: 500});
#override
_ColorDetailPageState createState() => new _ColorDetailPageState();
}
class _ColorDetailPageState extends State<ColorDetailPage> {
#override
Widget build(BuildContext context) {
final provider = AppStateProvider.of(context);
return Scaffold(
appBar: AppBar(
backgroundColor: widget.color,
title: Text(
'$widget.title[$widget.materialIndex]',
),
),
body: Container(
color: widget.color[widget.materialIndex],
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
provider.appState.appMode = widget.targetAppMode;
});
},
heroTag: null,
),
);
}
}
class ColorsListPage extends StatefulWidget {
final MaterialColor color;
final String title;
final ValueChanged<int> onPush;
final AppMode targetAppMode;
final List<int> materialIndices = [
100,
200,
300,
400,
500,
600,
700,
800,
900,
];
ColorsListPage({this.color, this.targetAppMode, this.title, this.onPush});
#override
_ColorsListPageState createState() => new _ColorsListPageState();
}
class _ColorsListPageState extends State<ColorsListPage> {
#override
Widget build(BuildContext context) {
final provider = AppStateProvider.of(context);
return new Scaffold(
appBar: AppBar(
title: Text(widget.title),
backgroundColor: widget.color,
),
body: Container(
color: Colors.white,
child: _buildList(context),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
provider.appState.appMode = widget.targetAppMode;
});
},
heroTag: null,
));
}
Widget _buildList(BuildContext context) {
return ListView.builder(
itemCount: widget.materialIndices.length,
itemBuilder: (BuildContext content, int index) {
int materialIndex = widget.materialIndices[index];
return Container(
color: widget.color[materialIndex],
child: ListTile(
title: Text(
"$materialIndex",
style: TextStyle(fontSize: 24.0),
),
trailing: Icon(Icons.chevron_right),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ColorDetailPage(
color: widget.color,
title: widget.title,
targetAppMode: widget.targetAppMode,
materialIndex: materialIndex,
)),
);
}
//onTap: () => onPush(materialIndex),
));
},
);
}
}

You need to wrap your InheritedWidget inside a StatefulWidget
class _AppStateProvider extends InheritedWidget {
final AppStateProviderState data;
_AppStateProvider({Key key, #required Widget child, #required this.data})
: super(key: key, child: child);
#override
bool updateShouldNotify(InheritedWidget oldWidget) => true;
}
class AppStateProvider extends StatefulWidget {
final Widget child;
final AppState appState;
AppStateProvider({
#required this.child,
#required this.appState,
});
static AppStateProviderState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_AppStateProvider)
as _AppStateProvider)
.data;
}
#override
AppStateProviderState createState() => AppStateProviderState(
appState,
);
}
class AppStateProviderState extends State<AppStateProvider> {
AppState appState;
AppStateProviderState(this.appState);
void updateAppMode(AppMode appMode) {
setState(() {
appState.appMode = appMode;
});
}
#override
Widget build(BuildContext context) {
return _AppStateProvider(
data: this,
child: widget.child,
);
}
}
for more information
pay attention to this method:
void updateAppMode(AppMode appMode) {
setState(() {
appState.appMode = appMode;
});
}
you can use it like this:
floatingActionButton: FloatingActionButton(
onPressed: () {
provider.updateAppMode(widget.targetAppMode);
},
heroTag: null,
),

Related

Flutter Switch will not work inside AlertBox

I am having a problem where when I try to use a switch widget it will not work properly inside of an alert box as in it does not switch over to the second state it just bounces whenever I try to flick it. I am wondering if this is because there is a problem with the switch itself or how I displayed it in the box? Thanks!
import 'package:flutter/material.dart';
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 Demo',
theme: ThemeData(),
home: SwitchDemo(),
);
}
}
class SwitchDemo extends StatefulWidget {
const SwitchDemo({Key key}) : super(key: key);
#override
State<StatefulWidget> createState() => new _TabsPageState();
}
class _TabsPageState extends State<SwitchDemo> {
bool isInstructionView;
#override
void initState() {
super.initState();
isInstructionView = Global.shared.isInstructionView;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("add data"),
),
body: Container(
child: TextButton(
child: Text('Open Alert Box'),
onPressed: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 20,
vertical:
MediaQuery.of(context).size.height / 20,
),
child: AlertDialog(
content: Container(
child: Switch(
value: isInstructionView,
onChanged: (bool isOn) {
if (isInstructionView == false) {
} else if (isInstructionView == true) {}
setState(() {
isInstructionView = isOn;
Global.shared.isInstructionView = isOn;
isOn = !isOn;
});
},
activeColor: Colors.blue,
inactiveTrackColor: Colors.grey,
inactiveThumbColor: Colors.grey,
),
),
),
);
})
}),
));
}
}
class Global {
static final shared = Global();
bool isInstructionView = false;
}
Wrap you AlertDialog with StatefulBuilder.
here is full code:
import 'package:flutter/material.dart';
class SwitchDemo extends StatefulWidget {
const SwitchDemo({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => new _TabsPageState();
}
class _TabsPageState extends State<SwitchDemo> {
late bool isInstructionView;
#override
void initState() {
super.initState();
isInstructionView = Global.shared.isInstructionView;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("add data"),
),
body: Container(
child: TextButton(
child: Text('Open Alert Box'),
onPressed: () => {
showDialog(
context: context,
builder: (BuildContext context) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: MediaQuery.of(context).size.width / 20,
vertical: MediaQuery.of(context).size.height / 20,
),
child: StatefulBuilder(builder: (context, setState) {
return AlertDialog(
content: Container(
child: Switch(
value: isInstructionView,
onChanged: (bool isOn) {
print(isInstructionView);
setState(() {
isInstructionView = !isInstructionView;
});
},
activeColor: Colors.blue,
inactiveTrackColor: Colors.grey,
inactiveThumbColor: Colors.grey,
),
),
);
}),
);
},
)
}),
));
}
}
class Global {
static final shared = Global();
bool isInstructionView = false;
}
Does it answer your question?
ref: https://stackoverflow.com/a/57240941/10157127

How can I give a Variable from one class to another and return the changed variable back?

I'm new to flutter and I'm trying to get the countdown-variable from the SetTimerPage to the CupertinoTimePickerButton-Page. Then change it there to the chosen time and give it back. Next I want to give the changed countdown to the next page where a countdown animation starts. I'm also open for suggestions to improve my syntax. Thank you :)
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.red,
),
home: SetTimerPage(),
);
}
}
class SetTimerPage extends StatefulWidget {
#override
_SetTimerPageState createState() => _SetTimerPageState();
}
class _SetTimerPageState extends State<SetTimerPage> {
final Duration countdown = Duration(minutes: 0, seconds: 0);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RoundONE'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CustomRowWidget(
icon: Icons.alarm_sharp,
text: 'COUNTDOWN',
button: CupertinoTimePickerButton(passedValue: countdown),
),
StartButton(countdown: countdown),
],
),
),
);
}
}
class CupertinoTimePickerButton extends StatefulWidget {
Duration passedValue;
CupertinoTimePickerButton({
Key key,
#required this.passedValue,
}) : super(key: key);
#override
_CupertinoTimePickerButtonState createState() =>
_CupertinoTimePickerButtonState();
}
class _CupertinoTimePickerButtonState extends State<CupertinoTimePickerButton> {
#override
Widget build(BuildContext context) {
return MaterialButton(
child: Text(
_formatDuration(widget.passedValue),
style: TextStyle(color: Colors.white),
),
color: Colors.redAccent,
onPressed: () {
_cupertinoTimeSetter(context);
},
);
}
Future _cupertinoTimeSetter(BuildContext context) {
return showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height / 2,
child: CupertinoTimerPicker(
onTimerDurationChanged: (Duration newDuration) {
setState(() {
widget.passedValue = newDuration;
});
},
minuteInterval: 1,
secondInterval: 5,
mode: CupertinoTimerPickerMode.ms,
),
);
},
);
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "$twoDigitMinutes:$twoDigitSeconds";
}
}
The best way is to use a call back that will give back the value to it's parent and for this case you can use ValueChanged. Then after the parent will be incharged to change the variable value.
class SetTimerPage extends StatefulWidget {
#override
_SetTimerPageState createState() => _SetTimerPageState();
}
class _SetTimerPageState extends State<SetTimerPage> {
Duration countdown;
#override
void initState() {
super.initState();
countdown = Duration(minutes: 0, seconds: 0);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RoundONE'),
),
body: Container(
padding: const EdgeInsets.all(16),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CustomRowWidget(
icon: Icons.alarm_sharp,
text: 'COUNTDOWN',
button: CupertinoTimePickerButton(
passedValue: countdown,
onChanged: (Duration duration) {
setState(() {
this.countdown = duration;
});
},
),
),
StartButton(countdown: countdown),
],
),
),
);
}
}
class CupertinoTimePickerButton extends StatelessWidget {
final Duration passedValue;
final ValueChanged<Duration> onChanged;
#override
Widget build(BuildContext context) {
return MaterialButton(
child: Text(
_formatDuration(widget.passedValue),
style: TextStyle(color: Colors.white),
),
color: Colors.redAccent,
onPressed: () {
_cupertinoTimeSetter(context);
},
);
}
Future _cupertinoTimeSetter(BuildContext context) {
return showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
height: MediaQuery.of(context).copyWith().size.height / 2,
child: CupertinoTimerPicker(
onTimerDurationChanged: this.onChanged,
minuteInterval: 1,
secondInterval: 5,
mode: CupertinoTimerPickerMode.ms,
),
);
},
);
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, "0");
String twoDigitMinutes = twoDigits(duration.inMinutes.remainder(60));
String twoDigitSeconds = twoDigits(duration.inSeconds.remainder(60));
return "$twoDigitMinutes:$twoDigitSeconds";
}
}

PushNamed issue: Type 'FillData' (a Statefulwidget) is not a subtype of type 'List<Object>'

I'm new in Flutter. I'm trying to push a List from NewData to FillData screen with pushNamed. But it said:
The following _TypeError was thrown while handling a gesture:
type 'FillData' is not a subtype of type 'List'
If i remove the comment in '/FillData', i receive null data instead. What should i do?
This is my code:
SettingNavigator
class SettingNavigator extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => Home(),
'/NewData': (context) => NewData(),
// '/FillData': (context) => FillData(), (in comment)
}
onGenerateRoute: (setting) {
if (setting.name == '/FillData') {
final ChartGroupData chartName = setting.arguments;
final List<ChartGroupData> groupNames = setting.arguments;
return MaterialPageRoute(builder: (context) {
return FillData(
chartName: chartName,
gName: groupNames,
);
});
}
return null;
},
);
}
}
NewData
import 'package:flutter/material.dart';
class NewData extends StatefulWidget {
List<ChartGroupData> groupNames;
NewData({Key key, #required this.groupNames}) : super(key: key);
#override
NewDataStage createState() => NewDataStage();
}
class NewDataStage extends State<NewData> {
TextEditingController _nameCtrl = new TextEditingController();
var textFields = <Widget>[];
var groupTECs = <TextEditingController>[];
#override
void initState() {
super.initState();
textFields.add(createCustomTextField());
}
Widget createCustomTextField() {
var groupCtrl = TextEditingController();
groupTECs.add(groupCtrl);
return Container(
padding: EdgeInsets.fromLTRB(0, 5, 0, 0),
child: Row(
children: <Widget>[
Expanded(flex: 3, child: Text("Group ${textFields.length}")),
Container(
constraints: BoxConstraints.tightFor(width: 120, height: 60),
child: TextField(
controller: groupCtrl,
),
),
],
),
);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Center(child: Text("New Chart")),
),
body: Container(
alignment: AlignmentDirectional.center,
constraints: BoxConstraints.expand(),
child: Column(
children: <Widget>[
Text(
"Your chart name",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
TextField(
style: TextStyle(fontSize: 20),
controller: _nameCtrl,
),
Expanded(
flex: 3,
child: Container(
child: ListView.builder(
shrinkWrap: true,
itemCount: textFields.length,
itemBuilder: (BuildContext context, int index) {
return textFields[index];
},
),
),
),
SizedBox(
height: 60,
width: 120,
child: RaisedButton(
onPressed: _onTapNext,
child: Text("NEXT"),
color: Colors.green,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _onTapCreate,
child: Icon(Icons.add, color: Colors.white),
shape: CircleBorder(),
),
),
);
}
void _onTapNext() {
/// Push Groups name to FillData
widget.groupNames = List<ChartGroupData>();
for (int i = 0; i < textFields.length; i++) {
var name = groupTECs[i].text;
widget.groupNames.add(ChartGroupData(name));
}
print(widget.groupNames.toString());
Navigator.pushNamed(context, '/FillData',
arguments: FillData(
gName: widget.groupNames,
chartName: ChartGroupData(_nameCtrl.text),
));
}
void _onTapCreate() {
setState(() {
textFields.add(createCustomTextField());
});
}
}
FillData
class FillData extends StatefulWidget {
final ChartGroupData chartName;
final List<ChartGroupData> gName;
FillData({Key key, #required this.chartName, #required this.gName})
: super(key: key);
#override
FillDataStage createState() => FillDataStage();
}
class FillDataStage extends State<FillData> {
void _showDialog() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Received Data"),
content: Text(widget.chartName.toString()),
);
},
);
}
void _onTapPrintReceivedData() {
print(widget.gName);
print(widget.chartName);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Center(
child: Text("Fill your Data"),
),
),
body: Center(
child: RaisedButton(
onPressed: () {
_onTapPrintReceivedData();
_showDialog();
},
child: Text("Print Data"),
),
),
));
}
}
Class ChartGroupData
lass ChartGroupData {
final String groupNames;
ChartGroupData(this.groupNames);
#override
String toString() {
return 'Group: $groupNames';
}
}
You have 2 problems with your code:
1- you cant user routes with onGenerateRoute, because now the app doesn't know where to go, to the widget that you didn't pass anything to (inside routes) or to the widget inside the onGenerateRoute.
2- arguments is a general object that you can put whatever you want inside of it, and doing this:
final ChartGroupData chartName = setting.arguments; final
List groupNames = setting.arguments;
passes the same value to two different objects, I solved this by doing the following (it's not the best but will give you a rough idea of what you should do)
created a new object that contains the data to be passed:
class ObjectToPass {
final ChartGroupData chartName;
final List<ChartGroupData> groupNames;
ObjectToPass({this.chartName, this.groupNames});
}
changed FillData implementation:
class FillData extends StatefulWidget {
final ObjectToPass objectToPass;
FillData({Key key, #required this.objectToPass}) : super(key: key);
#override
FillDataStage createState() => FillDataStage();
}
...
void _showDialog() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text("Received Data"),
content: Text(widget.objectToPass.chartName.toString()),
);
},
);
}
void _onTapPrintReceivedData() {
print(widget.objectToPass.groupNames);
print(widget.objectToPass.chartName);
}
to navigate to FillData you would:
Navigator.pushNamed(
context,
'/FillData',
arguments: ObjectToPass(
chartName: ChartGroupData(_nameCtrl.text),
groupNames: groupNames,
),
);
finally this is how your MaterialApp should look like:
return MaterialApp(
initialRoute: '/NewData',
onGenerateRoute: (setting) {
if (setting.name == '/FillData') {
return MaterialPageRoute(builder: (context) {
return FillData(
objectToPass: setting.arguments,
);
});
} else if (setting.name == '/NewData') {
return MaterialPageRoute(builder: (_) => NewData());
}
return null;
},
);
you can pass a list instead of the object I created and get your objects from it by it's index.

Height of the status bar always returns 0

When calling MediaQuery.of(context).padding.top in the parent widget (ProductsOverviewScreen) the value returned is as expected - 24. But when calling the same property from a nested widget (ProductsGrid) of the parent that we are talking about the value is always 0. Is this normal behavior?
products_overview_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../widgets/app_drawer.dart';
import '../screens/cart_screen.dart';
import '../widgets/products_grid.dart';
import '../widgets/badge.dart';
import '../providers/cart.dart';
import '../providers/products_provider.dart';
enum FilterOptions {
showAll,
onlyFavorites,
}
class ProductsOverviewScreen extends StatefulWidget {
#override
_ProductsOverviewScreenState createState() => _ProductsOverviewScreenState();
}
class _ProductsOverviewScreenState extends State<ProductsOverviewScreen> {
bool _showFavorites = false;
bool _isLoading = false;
bool _isInit = false;
#override
void initState() {
// Future.delayed(Duration(seconds: 1), () {
// Provider.of<Products>(context).fetchAndSetProducts();
// });
super.initState();
}
#override
void didChangeDependencies() {
if (!_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<Products>(context).fetchAndSetProducts().then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = true;
super.didChangeDependencies();
}
Future<void> refreshProducts(BuildContext context) async {
await Provider.of<Products>(context, listen: false).fetchAndSetProducts();
}
#override
Widget build(BuildContext context) {
final scaffoldKey = GlobalKey();
final appBar = AppBar(
title: Text('My Shop'),
actions: <Widget>[
Consumer<Cart>(
builder: (ctx, cart, child) => Badge(
child: child,
value: cart.length.toString(),
),
child: IconButton(
onPressed: () {
final scaffoldState = scaffoldKey.currentState as ScaffoldState;
scaffoldState.hideCurrentSnackBar();
Navigator.of(context).pushNamed(CartScreen.routeName);
},
icon: Icon(
Icons.shopping_cart,
color: Theme.of(context).accentColor,
),
),
),
PopupMenuButton(
onSelected: (FilterOptions selectedValue) {
setState(() {
if (selectedValue == FilterOptions.onlyFavorites) {
_showFavorites = true;
} else {
_showFavorites = false;
}
});
},
icon: Icon(Icons.more_vert),
itemBuilder: (_) => [
PopupMenuItem(
child: Text('Only Favorites'),
value: FilterOptions.onlyFavorites),
PopupMenuItem(
child: Text('Show All'),
value: FilterOptions.showAll,
),
],
),
],
);
return Scaffold(
key: scaffoldKey,
appBar: appBar,
drawer: AppDrawer(),
body: _isLoading
? Center(child: CircularProgressIndicator())
: RefreshIndicator(
onRefresh: () => refreshProducts(context),
child: ProductsGrid(_showFavorites, appBar.preferredSize.height),
),
);
}
}
//56
products_grid.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/products_provider.dart';
import '../widgets/product_item.dart';
class ProductsGrid extends StatelessWidget {
final bool _showFavorites;
final double _appBarHeight;
ProductsGrid(this._showFavorites, this._appBarHeight);
#override
Widget build(BuildContext context) {
final productsData = Provider.of<Products>(context);
final products =
_showFavorites ? productsData.favoriteItems : productsData.items;
final mediaQuery = MediaQuery.of(context);
return productsData.items.isEmpty
? SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: Container(
width: mediaQuery.size.width,
height: mediaQuery.size.height -
mediaQuery.padding.top -
_appBarHeight,
// child: Center(
// child: Text(
// 'There are no products.',
// style: TextStyle(
// color: Colors.grey,
// fontSize: 16,
// ),
// ),
// ),
),
)
: GridView.builder(
padding: const EdgeInsets.all(15),
itemCount: products.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10,
),
itemBuilder: (ctx, index) => ChangeNotifierProvider.value(
value: products[index],
child: ProductItem(),
),
);
}
}
You can copy paste run full code below
You can use MediaQueryData.fromWindow(window).padding.top
code snippet
import 'dart:ui';
...
final statusbarHeight2 = MediaQueryData.fromWindow(window).padding.top;
working demo
full code
import 'package:flutter/material.dart';
import 'dart:ui';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: ProductsOverviewScreen(title: 'Flutter Demo Home Page'),
);
}
}
class ProductsOverviewScreen extends StatefulWidget {
ProductsOverviewScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_ProductsOverviewScreenState createState() => _ProductsOverviewScreenState();
}
class _ProductsOverviewScreenState extends State<ProductsOverviewScreen> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
final statusbarHeight1 = MediaQueryData.fromWindow(window).padding.top;
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ProductsGrid(),
Text(
'$statusbarHeight1',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class ProductsGrid extends StatelessWidget {
const ProductsGrid({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
final statusbarHeight2 = MediaQueryData.fromWindow(window).padding.top;
return Text(
'$statusbarHeight2',
);
}
}
You can get all information about window using window object that provided by dart:ui. Here an example of finding exact size of status bar;
Firstly add this top of the dart file:
import 'dart:ui';
And use window object to find height of the status bar:
final statusBarHeight = window.padding.top / window.devicePixelRatio;

Child widget send dynamic data

I have a two-page app. On-Page One I am showing an UUID which changes every 1 second. It is shown using listview. Once the user clicks on the list view it goes to the second page and shows the data on that card.
It should have been the changing UUID. but the data shown is static UUID. How I can pass the data changed on page 1 to page 2?
import 'dart:async';
import 'package:uuid/uuid.dart';
import 'package:uuid/uuid_util.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
List<EuropeanCountries> europeanCountries = [];
class EuropeanCountries {
String myText;
String myUuid;
EuropeanCountries({
this.myText,
this.myUuid,
});
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
int _perPage = 50;
ScrollController _myScrollController = ScrollController();
void _incrementCounter() async {
const ThreeSec = const Duration(seconds: 1);
this._counter++;
europeanCountries.insert(
0,
EuropeanCountries(
myText: this._counter.toString(),
));
print(europeanCountries[0].myText);
setState(() {});
}
void getMoreData() {
print('adding More Product ');
europeanCountries.add(EuropeanCountries(
myText: this._counter.toString(),
));
//europeanCountries.insert(0, EuropeanCountries(myText:this._counter.toString(), myButtonText: "", myColor: Colors.blue));
setState(() {});
}
void generateUUID() async {
var uuid = Uuid();
for (int i = 0; i < 6000; i++) {
await new Future.delayed(new Duration(milliseconds: 1000));
for (EuropeanCountries currCountry in europeanCountries) {
currCountry.myUuid = uuid.v1();
}
setState(() {});
}
}
#override
void initState() {
// TODO: implement initState
super.initState();
generateUUID();
_myScrollController.addListener(() {
double maxscroll = _myScrollController.position.maxScrollExtent;
double currentScroll = _myScrollController.position.pixels;
double delta = MediaQuery.of(context).size.height * 0.25;
print("mac Scroll Controller - " + maxscroll.toString());
print("Current Scroll Controller - " + currentScroll.toString());
print("delta Scroll Controller - " + delta.toString());
if ((maxscroll - currentScroll) < delta) {
getMoreData();
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: _myListView(context),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
Widget _myListView(BuildContext context) {
// backing data
return Container(
child: europeanCountries.length == 0
? Center(
child: Text('No Product to Display'),
)
: ListView.builder(
controller: _myScrollController,
itemCount: europeanCountries.length,
reverse: false,
itemBuilder: (context, index) {
return myContainer(index: index);
},
),
);
}
}
class myContainer extends StatefulWidget {
final int index;
const myContainer({Key key, this.index}) : super(key: key);
#override
_myContainerState createState() => _myContainerState();
}
class _myContainerState extends State<myContainer> {
#override
Widget build(BuildContext context) {
return Container(
height: 120,
decoration: BoxDecoration(
border: Border.all(color: Colors.blue[700]),
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
margin: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Text(europeanCountries[widget.index].myText),
SizedBox(
height: 15,
),
RaisedButton(
child: Text('Detail'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondRoute(
myCountry: europeanCountries[widget.index],
)),
);
},
color: Colors.blue[700],
textColor: Colors.white,
padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
splashColor: Colors.black,
),
Text(europeanCountries[widget.index].myUuid != null
? europeanCountries[widget.index].myUuid
: 'Default')
],
),
);
}
}
class SecondRoute extends StatefulWidget {
final EuropeanCountries myCountry;
const SecondRoute({Key key, this.myCountry}) : super(key: key);
#override
_SecondRouteState createState() => _SecondRouteState();
}
class _SecondRouteState extends State<SecondRoute> {
#override
void didUpdateWidget(SecondRoute oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Second Route"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.pop(context);
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Text(widget.myCountry.myUuid != null
? widget.myCountry.myText
: 'default'),
),
SizedBox(height: 15),
Center(
child: Text(widget.myCountry.myUuid != null
? widget.myCountry.myUuid
: 'default'),
),
],
),
),
),
);
}
}
https://imgur.com/VqRfcZY
<blockquote class="imgur-embed-pub" lang="en" data-id="VqRfcZY"></blockquote><script async src="//s.imgur.com/min/embed.js" charset="utf-8"></script>