Skip to content

Instantly share code, notes, and snippets.

@ericwindmill
Created April 14, 2018 19:25
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save ericwindmill/f790bd2456e6489b1ab97eba246fd4c6 to your computer and use it in GitHub Desktop.
Save ericwindmill/f790bd2456e6489b1ab97eba246fd4c6 to your computer and use it in GitHub Desktop.
Flutter Simple inherited Widget Example
import 'package:flutter/material.dart';
import 'package:simple_inherit/state_container.dart';
class UpdateUserScreen extends StatelessWidget {
static final GlobalKey<FormState> formKey = new GlobalKey<FormState>();
static final GlobalKey<FormFieldState<String>> firstNameKey =
new GlobalKey<FormFieldState<String>>();
static final GlobalKey<FormFieldState<String>> lastNameKey =
new GlobalKey<FormFieldState<String>>();
static final GlobalKey<FormFieldState<String>> emailKey =
new GlobalKey<FormFieldState<String>>();
final User user;
const UpdateUserScreen({Key key, this.user}) : super(key: key);
@override
Widget build(BuildContext context) {
final container = StateContainer.of(context);
return new Scaffold(
appBar: new AppBar(
title: new Text('Edit User Info'),
),
body: new Padding(
padding: new EdgeInsets.all(16.0),
child: new Form(
key: formKey,
autovalidate: false,
child: new ListView(
children: [
new TextFormField(
key: firstNameKey,
style: Theme.of(context).textTheme.headline,
decoration: new InputDecoration(
hintText: 'First Name',
),
),
new TextFormField(
key: lastNameKey,
style: Theme.of(context).textTheme.headline,
decoration: new InputDecoration(
hintText: 'Last Name',
),
),
new TextFormField(
key: emailKey,
style: Theme.of(context).textTheme.headline,
decoration: new InputDecoration(
hintText: 'Email Address',
),
)
],
),
),
),
floatingActionButton: new FloatingActionButton(
child: new Icon(Icons.add),
onPressed: () {
final form = formKey.currentState;
if (form.validate()) {
var firstName = firstNameKey.currentState.value;
var lastName = lastNameKey.currentState.value;
var email = emailKey.currentState.value;
if (firstName == '') {
firstName = null;
}
if (lastName == '') {
lastName = null;
}
if (email == '') {
email = null;
}
container.updateUserInfo(
firstName: firstName,
lastName: lastName,
email: email,
);
Navigator.pop(context);
}
},
),
);
}
}
import 'package:flutter/material.dart';
import 'package:simple_inherit/form_page.dart';
import 'package:simple_inherit/state_container.dart';
void main() {
runApp(new StateContainer(child: new TodoApp()));
}
class TodoApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Some Todos',
home: new HomeScreen(),
);
}
}
class HomeScreen extends StatefulWidget {
@override
HomeScreenState createState() => new HomeScreenState();
}
class HomeScreenState extends State<HomeScreen> {
User user;
Widget get _userInfo {
return new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text("${user.firstName} ${user.lastName}",
style: new TextStyle(fontSize: 24.0)),
new Text(user.email, style: new TextStyle(fontSize: 24.0)),
],
),
);
}
Widget get _logInPrompt {
return new Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text('Please add user information'),
],
),
);
}
void _updateUser(BuildContext context) {
Navigator.push(
context,
new MaterialPageRoute(
fullscreenDialog: true,
builder: (context) {
return new UpdateUserScreen();
},
),
);
}
@override
Widget build(BuildContext context) {
final container = StateContainer.of(context);
user = container.user;
var body = user != null ? _userInfo : _logInPrompt;
return new Scaffold(
appBar: new AppBar(
title: new Text('Inherited Widget Test'),
),
body: body,
floatingActionButton: new FloatingActionButton(
onPressed: () => _updateUser(context),
child: new Icon(Icons.edit),
),
);
}
}
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
class User {
String firstName;
String lastName;
String email;
User(this.firstName, this.lastName, this.email);
}
class StateContainer extends StatefulWidget {
final Widget child;
final User user;
StateContainer({
@required this.child,
this.user,
});
static StateContainerState of(BuildContext context) {
return (context.inheritFromWidgetOfExactType(_InheritedStateContainer)
as _InheritedStateContainer)
.data;
}
@override
StateContainerState createState() => new StateContainerState();
}
class StateContainerState extends State<StateContainer> {
User user;
void updateUserInfo({firstName, lastName, email}) {
if (user == null) {
user = new User(firstName, lastName, email);
setState(() {
user = user;
});
} else {
setState(() {
user.firstName = firstName ?? user.firstName;
user.lastName = lastName ?? user.lastName;
user.email = email ?? user.email;
});
}
}
@override
Widget build(BuildContext context) {
return new _InheritedStateContainer(
data: this,
child: widget.child,
);
}
}
class _InheritedStateContainer extends InheritedWidget {
final StateContainerState data;
_InheritedStateContainer({
Key key,
@required this.data,
@required Widget child,
}) : super(key: key, child: child);
@override
bool updateShouldNotify(_InheritedStateContainer old) => true;
}
@lukepighetti
Copy link

Got anything simpler?

@Grumpf86
Copy link

Thank you for this example. :-)
Keeping a state in flutter is not that easy ... :P
I'm lucky the state of my hard drive is not that "volatile"

@function1983
Copy link

Thank you. Very good example and I feel very comfortable with just enough complexity. But for starters or absolute beginners, a diagram that map out the design for this particular app would be very helpful.

@xuesongcc
Copy link

Thank you for this example.:)
i have a problem:
https://gist.github.com/ericwindmill/f790bd2456e6489b1ab97eba246fd4c6#file-form_page-dart-L75
How does this function become optional?

@lifenautjoe
Copy link

Please rename to "Flutter Complex inherited Widget Example"

@cgustav
Copy link

cgustav commented Nov 10, 2019

Cool! it works for me! thanks

@benjamin-swain
Copy link

I found an issue. If you're on the 2nd page of a PageView and you press a button that runs container.updateUserInfo(), the PageView returns to its first page. I'm guessing this is because the PageView rebuilds and loses its state. How would you prevent PageView from returning to its first page in this case?

@dishangPatel
Copy link

dishangPatel commented Apr 26, 2020

Anyone have an idea why, this code directly returned true from updateShouldNotify method, without comparing data object?

@sagreine
Copy link

Nowadays you might use:

return (context.dependOnInheritedWidgetOfExactType<_InheritedStateContainer>()
            ).data;

instead of:

return (context.inheritFromWidgetOfExactType(_InheritedStateContainer)
            as _InheritedStateContainer)
        .data;

given inheritFromWidgetOfExactType is deprecated

@afroewis
Copy link

"StateContainerState"

@ergunacun
Copy link

This example is very cool. I understood the logic behind state management mechanisms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment