I keep getting the error as mentioned when I try to load LessonPage. What is happening is that I have a RootPage which checks if a user is signed in, if he is the RootPage will show the LessonPage but if he is not, it will show the LoginScreen which when the user logs in, will invoke a callback function to RootPage _onLoggedIn()so as to switch pages to the LessonPage.
Update: I found out that the error is also logged when I load the app (i.e. the app opens to a LoginScreen), however I see my login screen instead of a blank screen. I've appended my LoginScreen code below for reference
Root Page:
class RootPage extends StatefulWidget {
RootPage({this.auth});
final BaseAuth auth;
#override
State<StatefulWidget> createState() => new _RootPageState();
}
enum AuthStatus {
NOT_DETERMINED,
NOT_LOGGED_IN,
LOGGED_IN,
}
class _RootPageState extends State<RootPage> {
AuthStatus authStatus = AuthStatus.NOT_DETERMINED;
String _userId = "";
#override
void initState() {
super.initState();
widget.auth.getCurrentUser().then((user) {
setState(() {
if (user != null) {
_userId = user?.uid;
}
authStatus =
user?.uid == null ? AuthStatus.NOT_LOGGED_IN : AuthStatus.LOGGED_IN;
});
});
}
void _onLoggedIn() {
widget.auth.getCurrentUser().then((user){
setState(() {
_userId = user.uid.toString();
});
});
setState(() {
authStatus = AuthStatus.LOGGED_IN;
});
}
void _onSignedOut() {
setState(() {
authStatus = AuthStatus.NOT_LOGGED_IN;
_userId = "";
});
}
Widget _buildWaitingScreen() {
return Scaffold(
body: Container(
alignment: Alignment.center,
child:
ColorLoader5(
dotOneColor: Colors.blueGrey[600],
dotTwoColor: Colors.blueGrey[700],
dotThreeColor: Colors.blueGrey[800],
dotType: DotType.circle,
dotIcon: Icon(Icons.adjust),
duration: Duration(seconds: 1),
),
),
);
}
#override
Widget build(BuildContext context) {
switch (authStatus) {
case AuthStatus.NOT_DETERMINED:
return _buildWaitingScreen();
break;
case AuthStatus.NOT_LOGGED_IN:
return new LoginScreen(
auth: widget.auth,
onSignedIn: _onLoggedIn,
);
break;
case AuthStatus.LOGGED_IN:
if (_userId.length > 0 && _userId != null) {
return new Container(child: SingleChildScrollView(child: LessonPage(
title: LESSON_PAGE_TITLE,
userId: _userId,
auth: widget.auth,
onSignedOut: _onSignedOut,
)));
} else return _buildWaitingScreen();
break;
default:
return _buildWaitingScreen();
}
}
}
Lesson Page:
class LessonPage extends StatefulWidget {
LessonPage({Key key, this.auth, this.userId, this.onSignedOut, this.title}) : super(key: key);
final String title;
final BaseAuth auth;
final VoidCallback onSignedOut;
final String userId;
#override
_LessonPageState createState() => _LessonPageState();
}
class _LessonPageState extends State<LessonPage> {
List lessons;
#override
void initState() {
lessons = StaticMethods.getLessons();
super.initState();
}
#override
Widget build(BuildContext context) {
ListTile makeListTile(Lesson lesson) => ListTile(
contentPadding:
EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: Container(
padding: EdgeInsets.only(right: 12.0),
decoration: new BoxDecoration(
border: new Border(
right: new BorderSide(width: 1.0, color: Colors.white24))),
child: IconButton(
icon: Icon(Icons.file_download, color: Colors.white),
onPressed: (){},
),
),
title: Text(
lesson.title,
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
subtitle: Row(
children: <Widget>[
Expanded(
flex: 1,
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
)),
Expanded(
flex: 4,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(lesson.level,
style: TextStyle(color: Colors.white))),
)
],
),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailPage(lesson: lesson)));
},
);
Card makeCard(Lesson lesson) => Card(
elevation: 8.0,
margin: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 6.0),
child: Container(
decoration: BoxDecoration(color: Color.fromRGBO(64, 75, 96, .9)),
child: makeListTile(lesson),
),
);
final makeBody = Container(
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(lessons[index]);
},
),
);
final makeBottom = Container(
height: 55.0,
child: BottomAppBar(
color: Color.fromRGBO(58, 66, 86, 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(Icons.school, color: Colors.white),
onPressed: () => StaticMethods.goToWidget(context, new LessonPage(title: LESSON_PAGE_TITLE)),
),
IconButton(
icon: Icon(Icons.flight_takeoff, color: Colors.white),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.account_box, color: Colors.white),
onPressed: () {},
)
],
),
),
);
final topAppBar = AppBar(
elevation: 0.1,
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
title: Text(widget.title),
automaticallyImplyLeading: false,
);
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: topAppBar,
body: makeBody,
bottomNavigationBar: makeBottom,
);
}
}
LoginScreen Containers:
Widget OptionPage() {
return new Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Color.fromRGBO(58, 66, 86, 1.0),
image: DecorationImage(
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.1), BlendMode.dstATop),
image: AssetImage('assets/images/drones.jpg'),
fit: BoxFit.cover,
),
),
child: new Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 250.0),
child: Center(
child: Icon(
Icons.school,
color: Colors.white,
size: 40.0,
),
),
),
Container(
padding: EdgeInsets.only(top: 20.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
LOGIN_SCREEN_TITLE,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
],
),
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 30.0, right: 30.0, top: 150.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new OutlineButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Color.fromRGBO(58, 66, 86, 1.0),
highlightedBorderColor: Colors.white,
onPressed: () => gotoSignup(),
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
LOGIN_SCREEN_SIGN_UP,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 30.0, right: 30.0, top: 30.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton(
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0)),
color: Colors.white,
onPressed: () => gotoLogin(),
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
LOGIN_SCREEN_LOGIN,
textAlign: TextAlign.center,
style: TextStyle(
color: Color.fromRGBO(58, 66, 86, 1.0),
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
],
),
);
}
Widget LoginPage() {
return new Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
image: DecorationImage(
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.05), BlendMode.dstATop),
image: AssetImage('assets/images/drones.jpg'),
fit: BoxFit.cover,
),
),
child: new Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(120.0),
child: Center(
child: Icon(
Icons.school,
color: Color.fromRGBO(58, 66, 86, 1.0),
size: 50.0,
),
),
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
LOGIN_SCREEN_EMAIL,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextFormField( // LOGIN SCREEN EMAIL
maxLines: 1,
keyboardType: TextInputType.emailAddress,
autofocus: false,
textAlign: TextAlign.left,
decoration: InputDecoration(
icon: Icon(Icons.alternate_email),
hintText: LOGIN_SCREEN_EMAIL_HINT,
hintStyle: TextStyle(color: Colors.grey),
),
validator: (value) => value.isEmpty ? LOGIN_SCREEN_EMAIL_WARNING : null,
onSaved: (value) => _email = value,
),
),
],
),
),
Divider(
height: 24.0,
color: Color(0x00000000),
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
LOGIN_SCREEN_PASSWORD,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextFormField( // LOGIN SCREEN PASSWORD
obscureText: true,
keyboardType: TextInputType.emailAddress,
maxLines: 1,
autofocus: false,
textAlign: TextAlign.left,
decoration: InputDecoration(
icon: Icon(Icons.lock_outline),
hintText: LOGIN_SCREEN_PASSWORD_HINT,
hintStyle: TextStyle(color: Colors.grey),
),
validator: (value) => value.isEmpty ? LOGIN_SCREEN_PASSWORD_WARNING : null,
onSaved: (value) => _password = value,
),
),
],
),
),
Divider(
height: 24.0,
color: Color(0x00000000),
),
new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: new FlatButton(
child: new Text(
LOGIN_SCREEN_FORGOT_PASSWORD,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
textAlign: TextAlign.end,
),
onPressed: () => StaticMethods.locked(context),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 30.0, right: 30.0, top: 20.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton( // LOGIN SCREEN LOGIN BUTTON
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Color.fromRGBO(58, 66, 86, 1.0),
onPressed: () => _validateAndSubmit(),
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
LOGIN_SCREEN_LOGIN,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
Divider(
height: 25.0,
color: Color(0x00000000),
),
_showErrorMessage(),
Divider(
height: 25.0,
color: Color(0x00000000),
),
_showLoading(),
],
),
);
}
Widget SignupPage() {
return new Container(
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(
color: Colors.white,
image: DecorationImage(
colorFilter: new ColorFilter.mode(
Colors.black.withOpacity(0.05), BlendMode.dstATop),
image: AssetImage('assets/images/drones.jpg'),
fit: BoxFit.cover,
),
),
child: new Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(100.0),
child: Center(
child: Icon(
Icons.school,
color: Color.fromRGBO(58, 66, 86, 1.0),
size: 50.0,
),
),
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
LOGIN_SCREEN_EMAIL,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField( //SIGNUP SCREEN EMAIL
obscureText: true,
textAlign: TextAlign.left,
decoration: InputDecoration(
hintText: LOGIN_SCREEN_EMAIL_HINT,
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
color: Color(0x00000000),
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text(
LOGIN_SCREEN_PASSWORD,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField( // SIGNUP SCREEN PASSWORD
obscureText: true,
textAlign: TextAlign.left,
decoration: InputDecoration(
hintText: LOGIN_SCREEN_PASSWORD_HINT,
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
color: Color(0x00000000),
),
new Row(
children: <Widget>[
new Expanded(
child: new Padding(
padding: const EdgeInsets.only(left: 40.0),
child: new Text( // SIGNUP SCREEN CONFIRM PASSWORD
LOGIN_SCREEN_CONFIRM_PASSWORD,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 40.0, right: 40.0, top: 10.0),
alignment: Alignment.center,
padding: const EdgeInsets.only(left: 0.0, right: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
new Expanded(
child: TextField(
obscureText: true,
textAlign: TextAlign.left,
decoration: InputDecoration(
hintText: LOGIN_SCREEN_PASSWORD_HINT,
hintStyle: TextStyle(color: Colors.grey),
),
),
),
],
),
),
Divider(
height: 24.0,
color: Color(0x00000000),
),
new Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 20.0),
child: new FlatButton(
child: new Text(
LOGIN_SCREEN_HAVE_ACCOUNT,
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color.fromRGBO(58, 66, 86, 1.0),
fontSize: 15.0,
),
textAlign: TextAlign.end,
),
onPressed: () => StaticMethods.locked(context),
),
),
],
),
new Container(
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.only(left: 30.0, right: 30.0, top: 50.0),
alignment: Alignment.center,
child: new Row(
children: <Widget>[
new Expanded(
child: new FlatButton( // SIGNUP SCREEN SIGN UP BUTTON
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(30.0),
),
color: Color.fromRGBO(58, 66, 86, 1.0),
onPressed: () => StaticMethods.locked(context),
child: new Container(
padding: const EdgeInsets.symmetric(
vertical: 20.0,
horizontal: 20.0,
),
child: new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: Text(
LOGIN_SCREEN_SIGN_UP,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold),
),
),
],
),
),
),
),
],
),
),
],
),
);
}
PageController _controller = new PageController(initialPage: 1, viewportFraction: 1.0);
#override
Widget build(BuildContext context) {
_isIos = Theme.of(context).platform == TargetPlatform.iOS;
return Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: new Form (
key: _formKey,
child: PageView(
controller: _controller,
physics: new AlwaysScrollableScrollPhysics(),
children: <Widget>[LoginPage(), OptionPage(), SignupPage()],
scrollDirection: Axis.horizontal,
onPageChanged: (num){
switch (num) {
case 0:
setState(() {
_formKey.currentState.reset();
_errorMessage = "";
_formMode = FormMode.LOGIN;
});
break;
case 1:
setState(() {
_formKey.currentState.reset();
_errorMessage = "";
_formMode = FormMode.OPTIONS;
});
break;
case 2:
setState(() {
_formKey.currentState.reset();
_errorMessage = "";
_formMode = FormMode.SIGNUP;
});
break;
}
},
),
),
);
}
Error:
I/flutter (18510): The following assertion was thrown during performLayout():
I/flutter (18510): RenderCustomMultiChildLayoutBox object was given an infinite size during layout.
.....
In the error, it shows just a blank page instead of lesson page, and checking firebase I can see that a user logs in so I think it is some layout issue.
What I've tried:
RootPage (I still saw a blank screen):
return new LessonPage(
title: LESSON_PAGE_TITLE,
userId: _userId,
auth: widget.auth,
onSignedOut: _onSignedOut,
);
I tried to return a normal page instead of lesson page which just shows a loading animation which is already tested and works but still I see a blank page:
return _buildWaitingScreen();
LessonPage (still see blank page):
Widget makeBody(BuildContext context) => Container(
height: MediaQuery.of(context).size.height / 1.5,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(lessons[index]);
},
),
);
return Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: topAppBar,
body: makeBody(context),
bottomNavigationBar: makeBottom,
);
You dont need Container and SingleChildScrollView in below snippet:
return LessonPage(
title: LESSON_PAGE_TITLE,
userId: _userId,
auth: widget.auth,
onSignedOut: _onSignedOut,
);
If that didn't fix,
RenderCustomMultiChildLayoutBox object was given an infinite size during layout. means that you have used ListView or ScrollView or any other widget that has infinite size. In order to prevent this issue, wrap your makeBody list view with fixed size. If it is working you can use MediaQuery.of(context).size.height(gives device screen width) and adjest the size you want.
Ex:
Widget makeBody(BuildContext context) => Container(
height: MediaQuery.of(context).size.height / 1.5,
child: ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: lessons.length,
itemBuilder: (BuildContext context, int index) {
return makeCard(lessons[index]);
},
),
);
and call the method: body: makeBody(context),
Fix in RootPage:
return new Container(
height: MediaQuery.of(context).size.height,
child: LessonPage(
title: LESSON_PAGE_TITLE,
userId: _userId,
auth: widget.auth,
onSignedOut: _onSignedOut,
)
);
I'm developing an app and was following a sample from this link and ran into a problem where it says bottom overflowed by xx pixels as shown below:
Now, I encountered this before and solved it by adding SingleChildScrollView as shown below:
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Academy',
theme: new ThemeData(
primaryColor: Color.fromRGBO(58, 66, 86, 1.0)
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: new Container(
child: SingleChildScrollView(
child: LoginScreen(),
)
),
),
);
}
How do I do it when I'm not using a container but a column instead ? As that is what I'm using in the image above (column at the bottom of code, where the author returns the scaffold):
class DetailPage extends StatelessWidget {
final Lesson lesson;
DetailPage({Key key, this.lesson}) : super(key: key);
#override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: lesson.indicatorValue,
valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final coursePrice = Container(
padding: const EdgeInsets.all(7.0),
decoration: new BoxDecoration(
border: new Border.all(color: Colors.white),
borderRadius: BorderRadius.circular(5.0)),
child: new Text(
"\$" + lesson.price.toString(),
style: TextStyle(color: Colors.white),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Icon(
Icons.directions_car,
color: Colors.white,
size: 40.0,
),
Container(
width: 90.0,
child: new Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
lesson.title,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(flex: 1, child: levelIndicator),
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
lesson.level,
style: TextStyle(color: Colors.white),
))),
Expanded(flex: 1, child: coursePrice)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
padding: EdgeInsets.only(left: 10.0),
height: MediaQuery.of(context).size.height * 0.5,
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/images/drones1.jpg"),
fit: BoxFit.cover,
),
)),
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: Center(
child: topContentText,
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
lesson.content,
style: TextStyle(fontSize: 18.0),
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Color.fromRGBO(58, 66, 86, 1.0),
child:
Text("TAKE THIS LESSON", style: TextStyle(color: Colors.white)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, readButton],
),
),
);
return Scaffold(
body: Column( //here is the column
children: <Widget>[topContent, bottomContent],
),
);
}
}
I tried these but it does not work, giving me the same result as before:
return Scaffold(
body: Container(child: SingleChildScrollView(child:Column(children: <Widget>[topContent, bottomContent],),),),
);
return Scaffold(
body: Column(
children: <Widget>[Expanded(child: Column(children: <Widget>[topContent, bottomContent],))],
),
);
return Scaffold(
body: SingleChildScrollView(child: Container(child:Column(children: <Widget>[topContent, bottomContent],),),),
);
My outcome when I tried this as suggested:
return Scaffold(
body: Column( //here is the column
children: <Widget>[Expanded(child: SingleChildScrollView(child: Text("Test"))), Text("Data")],
),
);
I solved it by adding the SingleChildScrollView to the following in topContent:
Container(
height: MediaQuery.of(context).size.height * 0.5,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Color.fromRGBO(58, 66, 86, .9)),
child: SingleChildScrollView(
child: Center(
child: topContentText,
),
),
),
I have an app screen that uses Checkboxes and a Drop down Menu. However, I have realised I'd coded it inside a StatelessWidget so I am unable to change the state when an option is selected. How do I get this working so that when a Checkbox is selected then it will display as being "checked" rather than empty?
I have tried pasting in my code into a Stateful Widget, however keep running into errors, as I am not totally sure on which parts should go where.
import 'package:carve_brace_app/model/activity.dart';
import 'package:flutter/material.dart';
class DetailPage extends StatelessWidget {
final Activity activity;
DetailPage({Key key, this.activity}) : super(key: key);
#override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(
backgroundColor: Color.fromRGBO(209, 224, 224, 0.2),
value: 2.0,
valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Container(
width: 90.0,
child: new Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
activity.activityName,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
"Last Run: 3-2-19\n"+
"Last Avg Strain: 34%\n"+
"Last Run Time: 00:45:23",
style: TextStyle(color: Colors.white),
))),
// Expanded(flex: 1, child: newRow)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.45,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [
Color.fromRGBO(33, 147, 176, 100),
Color.fromRGBO(109, 213, 237, 100)
],
),
),
child: Center(
child: topContentText,
),
),
Positioned(
left: 235.0,
top: 180.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: new CircleAvatar(
radius: 80.0,
backgroundImage: NetworkImage(activity.icon),
backgroundColor: Colors.white,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
"Config:",
style: TextStyle(fontSize: 18.0),
);
final mappedCheckbox = CheckboxListTile(
title: Text("Mapped"),
value: false,
onChanged: (newValue) { },
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final rtCheckBox = CheckboxListTile(
title: Text("Real-time Tracking"),
value: false,
onChanged: (newValue) { },
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final descriptionText = Text(
"Description:",
style: TextStyle(fontSize: 12.0),
);
final description = TextFormField(
decoration: InputDecoration(
hintText: 'Enter an activity description',
),
);
final scheduledFor = Text(
"Scheduled for:",
style: TextStyle(fontSize: 12.0),
);
final dropdown = new DropdownButton<String>(
items: <String>['Now (Default)', 'B', 'C', 'D'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
hint: Text("Now (Default)"),
onChanged: (_) {},
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: 170,//MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Colors.lightBlue,
child:
Text("Start", style: TextStyle(color: Colors.white, fontSize: 20)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, mappedCheckbox, rtCheckBox, descriptionText, description, Text("\n"), scheduledFor, dropdown, readButton],
),
),
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
}
Hover on to the StatelessWidget class and use
Android Studio:
Mac: option + enter
Windows: alt + enter
Visual Studio Code:
Mac: cmd + .
Windows: ctrl + .
Output (Your solution):
Here is the working code.
class DetailPage extends StatefulWidget {
final Activity activity;
DetailPage({Key key, this.activity}) : super(key: key);
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
bool _tracking = false, _mapped = false; // you need this
String _schedule;
#override
Widget build(BuildContext context) {
final levelIndicator = Container(
child: Container(
child: LinearProgressIndicator(backgroundColor: Color.fromRGBO(209, 224, 224, 0.2), value: 2.0, valueColor: AlwaysStoppedAnimation(Colors.green)),
),
);
final topContentText = Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 120.0),
Container(
width: 90.0,
child: Divider(color: Colors.green),
),
SizedBox(height: 10.0),
Text(
widget.activity.activityName,
style: TextStyle(color: Colors.white, fontSize: 45.0),
),
SizedBox(height: 30.0),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 6,
child: Padding(
padding: EdgeInsets.only(left: 10.0),
child: Text(
"Last Run: 3-2-19\n" + "Last Avg Strain: 34%\n" + "Last Run Time: 00:45:23",
style: TextStyle(color: Colors.white),
))),
// Expanded(flex: 1, child: newRow)
],
),
],
);
final topContent = Stack(
children: <Widget>[
Container(
height: MediaQuery.of(context).size.height * 0.45,
padding: EdgeInsets.all(40.0),
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.centerLeft,
end: Alignment.centerRight,
colors: [Color.fromRGBO(33, 147, 176, 100), Color.fromRGBO(109, 213, 237, 100)],
),
),
child: Center(
child: topContentText,
),
),
Positioned(
left: 235.0,
top: 180.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: CircleAvatar(
radius: 80.0,
backgroundColor: Colors.white,
),
),
),
Positioned(
left: 8.0,
top: 60.0,
child: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Icon(Icons.arrow_back, color: Colors.white),
),
)
],
);
final bottomContentText = Text(
"Config:",
style: TextStyle(fontSize: 18.0),
);
final mappedCheckbox = CheckboxListTile(
title: Text("Mapped"),
value: _mapped,
onChanged: (newValue) => setState(() => _mapped = newValue),
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final rtCheckBox = CheckboxListTile(
title: Text("Real-time Tracking"),
value: _tracking,
onChanged: (newValue) => setState(() => _tracking = newValue),
controlAffinity: ListTileControlAffinity.leading, // <-- leading Checkbox
);
final descriptionText = Text(
"Description:",
style: TextStyle(fontSize: 12.0),
);
final description = TextFormField(
decoration: InputDecoration(
hintText: 'Enter an activity description',
),
);
final scheduledFor = Text(
"Scheduled for:",
style: TextStyle(fontSize: 12.0),
);
final dropdown = DropdownButton<String>(
value: _schedule,
items: <String>['Now (Default)', 'B', 'C', 'D'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
hint: Text("Now (Default)"),
onChanged: (newValue) {
setState(() {
_schedule = newValue;
});
},
);
final readButton = Container(
padding: EdgeInsets.symmetric(vertical: 16.0),
width: 170, //MediaQuery.of(context).size.width,
child: RaisedButton(
onPressed: () => {},
color: Colors.lightBlue,
child: Text("Start", style: TextStyle(color: Colors.white, fontSize: 20)),
));
final bottomContent = Container(
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.all(40.0),
child: Center(
child: Column(
children: <Widget>[bottomContentText, mappedCheckbox, rtCheckBox, descriptionText, description, Text("\n"), scheduledFor, dropdown, readButton],
),
),
);
return Scaffold(
body: Column(
children: <Widget>[topContent, bottomContent],
),
);
}
}
For VSCode (Visual Studio Code) use ctrl + '.' keys while the cursor on the stateless widget to convert it to stateful widget.
You could use intellij's or vscode shortcut by hitting alt + enter or selecting the bulb icon while your cursor is on the name of the stateless widget then select convert to stateful widget
For Android Studio in Mac:
1.Place the marker on the Stateless widget name
2.Hit Alt+Enter
3.Select Convert to Stateful widget
4.Configure your Stateful widget based on your requirements
Adding a solution for Android Studio since I didn't find one here.
Place the marker on the Stateless widget name:
Hit Alt+Enter
Select Convert to Stateful widget
Configure your Stateful widget based on your requirements
Map item;
List data;
Future getdata() async{
http.Response response= await http.get(Uri.encodeFull("https://talaikis.com/api/quotes/"));
item=json.decode(response.body);
setState(() {
data=item["quotes"];
});
debugPrint(data.toString());
}
I want to display this request in stateful widget which is like this
#override
Widget build(BuildContext context) {
return new Scaffold(
drawer: drawerLeft(),
appBar: AppBar(
title: Text(
"IN TIME",
style: TextStyle(color: Colors.black, fontWeight: FontWeight.w700),
),
backgroundColor: clr,
elevation: 0.0,
leading: MaterialButton(
child: Icon(
Icons.view_headline,
color: Colors.black,
),
onPressed: () {
scaffoldKey.currentState.openDrawer();
},
)),
key: scaffoldKey,
body: AnimatedContainer(
padding: EdgeInsets.only(top: 50.0),
duration: Duration(milliseconds: 1000),
curve: Curves.ease,
color: clr,
child: PageView.builder(
itemCount: 7, //7days
onPageChanged: (int page) {
this.setState(() {
Random rnd;
rnd = new Random();
int r = 0 + rnd.nextInt(_colors.length - 0);
clr = _colors[r];
});
},
controller: pageViewController,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.only(left: 10.0),
child: Stack(
children: <Widget>[
Container(
decoration: new BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
color: Colors.white,
),
height:
MediaQuery.of(scaffoldKey.currentContext).size.height -
150.0,
width:
MediaQuery.of(scaffoldKey.currentContext).size.width -
20.0,
child: Stack(
children: <Widget>[
Positioned(
width: MediaQuery.of(scaffoldKey.currentContext)
.size
.width -
100.0,
left: index != currentPage
? getMappedValue(20.0, 100.0, 160.0, 20.0, pos)
: getMappedValue(20.0, 100.0, 20.0, -120.0, pos),
top: 20.0,
child: Opacity(
opacity: index != currentPage
? getMappedValue(20.0, 100.0, 0.0, 01.0, pos)
: getMappedValue(20.0, 100.0, 01.0, 00.0, pos),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
_days[index],
maxLines: 1,
softWrap: true,
style: TextStyle(
color: Colors.deepOrange,
fontSize: 22.0,
fontWeight: FontWeight.w600),
),
],
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text(
'Quote for the day',
softWrap: true,
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.w300),
),
),
],
),
),
),
],
),
),
],
),
);
},
),
),
);
}
}
*Please help me out *
If I understand, you want to display the quotes under some padding that are being retrieved to your List which I'll assume to be an inferenced List<String>. If so, you could just use a ListView within your widget tree to display every fetched item in that list, like so:
(...)
data != null
? Padding(
padding: const EdgeInsets.only(top: 15.0),
child: ListView.builder(
itemCount: data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(data[index]),
);
},
),
)
: Container(),
(...)