Related
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,
)
);
Here's a mockup of the dialog I'm trying to create in Flutter:
Here's what I have so far:
I'm unable to position my two button's with rounded bottom corners at the bottom of the dialog so that it looks like in the mockup.
I was able to make those buttons fit within the Dialog width, without the stack, but then it would be positioned at the top.
Here's the code for the dialog:
SimpleDialog carDialog = SimpleDialog(
contentPadding: EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
children: <Widget>[
Container(
height: 400,
child: Stack(
children: <Widget>[
Positioned(
bottom: 0,
child: IntrinsicWidth(
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(6)),
color: Colors.lightBlueAccent,
),
height: 45,
child: Center(
child: Text(
allTranslations.text('wait_enroute').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(6)),
color: AppColors.action_button,
),
height: 45,
child: Center(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
allTranslations.text('new_order').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
],
),
),
),
],
),
),
],
);
showDialog(context: context, builder: (context) => carDialog);
I have found a working solution. It does not require the Stack widget, everything can be nested within a Column like so:
SimpleDialog carDialog = SimpleDialog(
contentPadding: EdgeInsets.all(0),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(6)),
children: <Widget>[
Column(
children: <Widget>[
SizedBox(
height: 400,
),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: InkWell(
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(bottomLeft: Radius.circular(6)),
color: Colors.lightBlueAccent,
),
height: 45,
child: Center(
child: Text(
allTranslations.text('wait_enroute').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.only(bottomRight: Radius.circular(6)),
color: AppColors.action_button,
),
height: 45,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
allTranslations.text('new_order').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
],
),
],
),
],
);
showDialog(context: context, builder: (context) => carDialog);
The result:
You can try this replacing with Row
LayoutBuilder(
builder:(BuildContext context, BoxConstraints constraints){
return Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
SizedBox(
width : constraints.maxWidth/2
child:Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(6)),
color: Colors.lightBlueAccent,
),
height: 45,
child: Center(
child: Text(
allTranslations.text('wait_enroute').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
SizedBox(
width : constraints.maxWidth/2
child:Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(6)),
color: AppColors.action_button,
),
height: 45,
child: Center(
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8.0),
child: Text(
allTranslations.text('new_order').toUpperCase(),
textAlign: TextAlign.center,
style: Fonts.appFont(context,
bold: true, color: Colors.white),
),
),
),
),
),
],
);
}
),
I'm familiar with Column and Row.
But the complex UI in my image example, I don't know how to begin, ignoring the Chinese words.
Will this work?
double _appBarHeight = 120, _imageHeight = 80, _iconTopMargin = 44, _iconLeftMargin = 12, _leftMargin = 120;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Positioned(
left: 0,
right: 0,
height: _appBarHeight,
child: Container(color: Colors.blue),
),
Positioned(
left: _iconLeftMargin,
top: _iconTopMargin,
child: Icon(Icons.settings, color: Colors.white),
),
Positioned(
right: _iconLeftMargin,
top: _iconTopMargin,
child: Icon(Icons.bubble_chart, color: Colors.white),
),
Positioned(
left: _iconLeftMargin,
top: _appBarHeight - _imageHeight / 2,
child: ClipOval(child: Image.asset("assets/images/profile.jpg", fit: BoxFit.cover, height: _imageHeight, width: _imageHeight)),
),
Positioned(
left: _leftMargin,
top: _appBarHeight - (_imageHeight / 2),
child: Text("CopsOnRoad", style: TextStyle(color: Colors.white, fontWeight: FontWeight.w500, fontSize: 18)),
),
Positioned.fill(
left: _leftMargin,
top: _appBarHeight + (_imageHeight / 4),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Column(
children: <Widget>[
Text("2", style: TextStyle(fontWeight: FontWeight.bold)),
Text("Gold", style: TextStyle(color: Colors.grey)),
],
),
Column(
children: <Widget>[
Text("22", style: TextStyle(fontWeight: FontWeight.bold)),
Text("Silver", style: TextStyle(color: Colors.grey)),
],
),
Column(
children: <Widget>[
Text("28", style: TextStyle(fontWeight: FontWeight.bold)),
Text("Bronze", style: TextStyle(color: Colors.grey)),
],
),
Container(),
],
),
),
Positioned(
left: 0,
top: _appBarHeight + _imageHeight / 1.1,
right: 0,
height: 1,
child: Container(color: Colors.grey),
),
Positioned(
top: _appBarHeight + _imageHeight * 1.1,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Text("Reputation", style: TextStyle(color: Colors.grey)),
),
),
Positioned.fill(
left: _leftMargin,
top: _appBarHeight + _imageHeight * 1.1,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text("This", style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(width: 10),
Container(width: 1, color: Colors.grey.withOpacity(0.4), height: 16),
SizedBox(width: 10),
Text("is", style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(width: 10),
Container(width: 1, color: Colors.grey.withOpacity(0.4), height: 16),
SizedBox(width: 10),
Text("5509", style: TextStyle(fontWeight: FontWeight.bold)),
SizedBox(width: 10),
Spacer(),
Icon(Icons.keyboard_arrow_right, color: Colors.grey)
],
),
),
],
),
);
}
You can use the Stack widget and a Positioned element to help you position the avatar in the right place.
A quick video on the Positioned and Stack: https://www.youtube.com/watch?v=EgtPleVwxBQ
When I create a Container with box shadow inside a ListView (scrolls Horizontally), the shadow looks fine, but, when I add multiple Containers inside the ListView, their shadows(just shadows, not Container) gets cropped at top and bottom.
Please also note that this whole ListView is wrapped under a parent Container.
I tried to increase the height of Parent Container(in which the whole ListView is wrapped), but it increases the height of child Container with its shadow still cropped.
I also tried to give padding to Parent Container but, it still shadow still gets cropped.
Maybe I need to wrap the ListView inside any other Widget which can get the job done without the problem.
Container(
// padding: EdgeInsets.only(left: 30.0, right: 0.0),
height: 140.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
SizedBox(
width: 30.0,
),
Container(
//This is actual custom Card
width: 340.0,
height: 140.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset.zero,
blurRadius: 10.0,
spreadRadius: 0.0,
)
],
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(
30.0, 20.0, 25.0, 20.0),
child: Image.asset(
'assets/images/leather_boot.png'),
),
Container(
padding:
EdgeInsets.only(top: 30.0, bottom: 30.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
'BadAss Genuine',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
SizedBox(
height: 3.0,
),
Text(
'Leather Boots',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
SizedBox(
height: 12.0,
),
Container(
height: 1.5,
width: 150.0,
color: Color(0xff643523),
),
],
),
),
],
),
),
SizedBox(
width: 30.0,
),
Container(
//This is actual custom Card
width: 340.0,
height: 140.0,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
color: Colors.black12,
offset: Offset.zero,
blurRadius: 10.0,
spreadRadius: 0.0,
)
],
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(
30.0, 20.0, 25.0, 20.0),
child: Image.asset(
'assets/images/leather_boot.png'),
),
Container(
padding:
EdgeInsets.only(top: 30.0, bottom: 30.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
'BadAss Genuine',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
SizedBox(
height: 3.0,
),
Text(
'Leather Boots',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w500,
fontSize: 18.0,
),
),
SizedBox(
height: 12.0,
),
Container(
height: 1.5,
width: 150.0,
color: Color(0xff643523),
),
],
),
),
],
),
),
SizedBox(
width: 30.0,
),
],
),
),
I expect the ListView to have Containers(as custom Cards) to have proper BoxShadow, but in the actual output, Containers' BoxShadow gets cropped from both Top & Bottom.
As #Zahra wrote,
adding clipBehavior: Clip.none, to the ListView, solved the problem.
The crop happens only when your widgets exceed the screen size
Okay I found the solution myself.
Steps to fix the problem
Create several Container(as a card) with some width and with a BoxShadow of Radius 10.0. Lets call it Child Container.
Create a ListView with Horizontal scroll axis. Put Child Containers made above in this ListView.
Now wrap the ListView inside a new Container(Lets call it Parent Container) to give ListView a height. If you want your Child Containers to be of height 140.0, then make your Parent Container's height 160.0, which includes radius of BoxShadow of 10.0 on top & bottom each(10.0+ 140.0 + 10.0).
Now give padding to your ListView of 10.0 on both top & bottom.
Problem Solved (Silly Me).
Sample Code here
Container(
height: 160.0,
child: ListView(
padding: EdgeInsets.only(top: 10.0, bottom: 10.0),
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: <Widget>[
SizedBox(
width: 30.0,
),
Container(
width: 340.0,
// height: 140.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
blurRadius: 10.0,
color: Colors.black12,
)
],
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(
30.0, 20.0, 25.0, 20.0),
child: Image.asset(
'assets/images/leather_boot.png'),
),
Container(
padding:
EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
'BadAss Genuine',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 18.0,
),
),
SizedBox(
height: 3.0,
),
Text(
'Leather Boots',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 18.0,
),
),
SizedBox(
height: 12.0,
),
Container(
height: 1.0,
width: 150.0,
color: Color(0xff643523),
),
SizedBox(
height: 12.0,
),
Row(
children: <Widget>[
SizedBox(
width: 110.0,
),
Container(
height: 30.0,
width: 30.0,
child: Image.asset(
'assets/images/boot.png'),
),
],
),
],
),
),
],
),
),
SizedBox(
width: 30.0,
),
Container(
//This is actual custom Card
width: 340.0,
// height: 140.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
blurRadius: 10.0,
color: Colors.black12,
)
],
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(
30.0, 20.0, 25.0, 20.0),
child:
Image.asset('assets/images/gloves.png'),
),
Container(
padding:
EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
'Highly Durable',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 18.0,
),
),
SizedBox(
height: 3.0,
),
Text(
'Riding Gloves',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 18.0,
),
),
SizedBox(
height: 12.0,
),
Container(
height: 1.0,
width: 150.0,
color: Color(0xff643523),
),
SizedBox(
height: 12.0,
),
Row(
children: <Widget>[
SizedBox(
width: 110.0,
),
Container(
height: 30.0,
width: 30.0,
child: Image.asset(
'assets/images/glove.png'),
),
],
),
],
),
),
],
),
),
SizedBox(
width: 30.0,
),
Container(
//This is actual custom Card
width: 340.0,
// height: 140.0,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
blurRadius: 10.0,
color: Colors.black12,
)
],
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(
30.0, 20.0, 25.0, 20.0),
child:
Image.asset('assets/images/helmet.png'),
),
Container(
padding:
EdgeInsets.only(top: 20.0, bottom: 20.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
Text(
'German Hat',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 18.0,
),
),
SizedBox(
height: 3.0,
),
Text(
'Riding Helmet',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w400,
fontSize: 18.0,
),
),
SizedBox(
height: 12.0,
),
Container(
height: 1.0,
width: 150.0,
color: Color(0xff643523),
),
SizedBox(
height: 12.0,
),
Row(
children: <Widget>[
SizedBox(
width: 110.0,
),
Container(
height: 30.0,
width: 30.0,
child: Image.asset(
'assets/images/helmeticon.png'),
),
],
),
],
),
),
],
),
),
SizedBox(
width: 30.0,
),
],
),
),
I am using BottomNavigationBarItem to display bottom navigation UI with icons and text. I would like to be able to add badges with numeric values on those. Here is my current attempt:
bottomNavigationBar:
new BottomNavigationBar(items: <BottomNavigationBarItem>[
new BottomNavigationBarItem(
icon: new Stack(
children: <Widget>[
const Icon(Icons.home),
new Positioned(
top: 0.0,
left: 0.0,
child: new Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(4.0),
color: Colors.red),
width: 16.0,
child: new Text(
"12",
style: const TextStyle(color: Colors.white),
),
))
],
),
title: new Text("Home")),
new BottomNavigationBarItem(
icon: const Icon(Icons.star), title: new Text("Star")),
],
type: BottomNavigationBarType.fixed),
However, the badge is positioned with the icon's bounding box, so it overlaps heavily with the icon:
What I would like, instead, is something like that:
Is it possible to achieve this using the BottomNavigationBarItem widget? If not, what would be a good workaround?
make sure that the badge position is right, and the overflowing children should be visible
icon: new Stack(
overflow: Overflow.visible,
children: <Widget>[
const Icon(Icons.home),
new Positioned(
top: -1.0,
right: -6.0,
child: new Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(4.0), color: Colors.red),
width: 16.0,
child: new Text(
"12",
style: const TextStyle(color: Colors.white),
),
))
],
),
If it is useful to anyone, I made one that works in the AppBar.
static Widget makeIconWithBadge(String badgeText, GestureTapCallback onTap) {
return Container(
padding: EdgeInsets.only(right: 16.0),
child: Center(
child: new Stack(
overflow: Overflow.visible,
children: <Widget>[
const Icon(Icons.inbox),
new Positioned(
top: -6.0,
right: -6.0,
child: Container(
padding: EdgeInsets.all(2.0),
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(99.0),
color: Colors.white,
),
child: new Container(
padding: EdgeInsets.symmetric(vertical: 1.0, horizontal: 4.0),
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(99.0),
color: Colors.red),
child: Center(
child: new Text(
"12",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 12.0,),
),
),
),
),
),
Positioned.fill(
child: Material(
borderRadius: BorderRadius.all(Radius.circular(99.0)),
color: Colors.transparent,
child: InkWell(onTap: onTap),
),
)
],
),
),
);
}