How to handle dynamic images within a FittedBox - ios

I am currently implementing a dropdown button as the title of a scaffold.
In this dropdown, some of the options do not have a relevant image and therefore just text is shown. I have it working great, my only problem is, an error is always thrown when the app runs (not hot reloaded) because the Image doesn't load instantaneously meaning that FittedBox is trying to fit an empty widget, once it loads it is fine, and then hot reloads work fine with no errors too because the image is already loaded. Here is my code for my DropDownMenuItems:
return DropdownMenuItem(
value: company.id.toString(),
child: Center(
child: FittedBox(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: (config.companyLogos[company.id] != null)
? FittedBox(
child: Image.asset(
config.companyLogosPath +
config.companyLogos[company.id],
height: 50,
),
fit: BoxFit.contain,
)
: FittedBox(
child: Text(
company.name,
style: TextStyle(fontSize: 30),
)),
),
],
)))));
And here is the error that is thrown when the app runs, I am sure this is due to what I described above:
flutter: ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
flutter: The following assertion was thrown during performLayout():
flutter: 'package:flutter/src/rendering/box.dart': Failed assertion: line 313 pos 12: 'width > 0.0': is not
flutter: true.
Considered solutions:
A possible solution would be to supply the width of image, I could include this in my companyLogos map by making it a Map of Maps and including the filename and the width in the sub map.
However, I've trie this and it doesn't seem to work, it just makes my images a lot smaller than if I used an unset width.
I am not explicitly defining width to make it keep its aspect ratio whilst still fitting in the row.
I'm probably missing a trick here on how to handle images in flutter/dart, any help would be much appreciated, thank you!

Thanks to #pskink I have solved the issue.
I solved it by scrapping the FittedBox completely and using Image's 'fit:' property.
Here is my fixed code:
return DropdownMenuItem(
value: company.id.toString(),
child: Center(
child: FittedBox(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
margin: EdgeInsets.all(10),
child: (config.companyLogos[company.id] != null)
? Container(
child: Image.asset(
config.companyLogosPath +
config.companyLogos[company.id],
height: 50,
fit: BoxFit.contain,
))
: FittedBox(
child: Text(
company.name,
style: TextStyle(fontSize: 30),
)),
),
],
)))));

Related

How to center a Widget vertically in PreferredSizeWidget

I want to center a Text vertically in the bottom: Sektion of my AppBar.
Some things I allready tried are:
1. wrap the Text in a Center(...) Widget
2. wrap the Text in a Column(...) and use crossAxisAlignment: CrossAxisAlignment.center
The bottom: Sektion is a PreferredSizeWidget and does not provide anything to format a Widget.
appBar: new AppBar(
actions: <Widget>[
IconButton(
icon: Icon(Icons.settings),
onPressed: () {
print("Settings Icon");
},
),
],
bottom: PreferredSize(
preferredSize: Size(130.0, 130.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Text(
'N/A',
),
],
),
),
),
I have have found this issue here: https://github.com/flutter/flutter/issues/16262 where the Text was centered but the reproduce code did not worked out for me.
The Text should me somewhere like the red line is (see Image)
Thank you!
PreferredSizeWidget does not impose a size constraint on its child, so you must wrap the Column in a widget with defined height in order to add alignment.
Also, mainAxisAlignment should be used, since this is the vertical alignment in a Column.
bottom: PreferredSize(
preferredSize: Size(130.0, 130.0),
child: Container(
height: 130,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text(
'N/A',
),
],
),
),
)

Flutter - Layout in the Emulator & Phones are different

I'm making a new project in Flutter. Every widget that i made is work perfectly.. but there's some issue when i want to place two images Container in Row, it's perfectly fine on Emulator with 1080x1920, but when i open it on my 460x854 phone...it's crashing with the Symmetric Padding. I've reading some about MediaQuery, but because i'm a beginner, i can't implement it.
Can someone help me?
Here is the code(the full code is too long):
return new Scaffold(
body: ListView(
children: <Widget>[
new Stack(
children: <Widget>[
Container(
child: Column(
children: <Widget>[
//sdsds
new Row(
children: <Widget>[
Expanded(
child: Row(
//HERE IS THE IMAGE IN ROW
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Container(
height: 160.0,
width: 160.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('intro/1pew.png'),
)),
),
new Container(
height: 160.0,
width: 160.0,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('intro/2pew.png'),
)),
Here is the screenshot (btw, ignore those pewds):
Rather than set the height and width. I would use a Row, then add Expanded widgets, with AspectRatio childs to force behaviour.
example:
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: Image.asset("assets/image1.png"),
),
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: Image.asset("assets/image2.png"),
),
)
],
);
}
This forces both items in the Row to be the same size as both Expanded the AspectRatio widget will force a square, then your view can fill that square.
for detail about mediaquery
to use media query
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
for screen adjustment you can add
height: MediaQuery.of(context).size.height/number (e.g 2 or 3, whatever),
width: MediaQuery.of(context).size.width/2,

how can I make BottomNavigationBar stick on top of keyboard flutter

I am trying to make a simple chat app, so I created a scaffold and my body, will be the messages and my bottomNavigationBar would be my typing field and sending icon.
I added a text field but when typing the navigation bar is hidden by the keyboard.
this is the code of my BottomNavigationBar :
bottomNavigationBar: new Container(
height: ScreenSize.height/12,
/*color: Colors.red,*/
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
child: new Icon(Icons.send),
width:ScreenSize.width/6,
),
],
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Material(
child: new Container(
child: new TextField(
autofocus: false,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(9.0),
border: InputBorder.none,
hintText: 'Please enter a search term',
),
),
width:ScreenSize.width*4/6,
),
elevation: 4.0,
/*borderRadius: new BorderRadius.all(new Radius.circular(45.0)),*/
clipBehavior: Clip.antiAlias,
type: MaterialType.card,
)
],
),
new Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
new Container(
child: Text('HELLO C1'),
color: Colors.green,
width:ScreenSize.width/6,
),
],
)
],
),
),
here is how it looks when focused :
if you use a Stack on your Scaffold's body, instead of bottomNavigationBar, your nav will push up above the keyboard. even if you fix to the bottom with a Positioned:
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: MyNav(),
),
simply wrap your bottom navigation bar with Padding and set it to MediaQuery.of(context).viewInsets,
bottomNavigationBar: Padding(
padding: MediaQuery.of(context).viewInsets,
child: ChatInputField(),
),
Literally just worked through the same issue. Given the code i was refactoring, this worked like a charm. Peep the github link, review his change and apply. Couldn't be much more straight forward: https://github.com/GitJournal/GitJournal/commit/f946fe487a18b2cb8cb1d488026af5c64a8f2f78..
Content of the link above in case the link goes down:
(-)BottomAppBar buildEditorBottonBar(
(+)Widget buildEditorBottonBar(
BuildContext context,
Editor editor,
EditorState editorState,
BottomAppBar buildEditorBottonBar(
folderName = "Root Folder";
}
*REPLACE* return BottomAppBar(
elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor,
child: Row(
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.folder),
label: Text(folderName),
onPressed: () {
var note = editorState.getNote();
editor.moveNoteToFolderSelected(note);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
*WITH THE WRAPPER* return StickyBottomAppBar(
child: BottomAppBar(
elevation: 0.0,
color: Theme.of(context).scaffoldBackgroundColor,
child: Row(
children: <Widget>[
FlatButton.icon(
icon: Icon(Icons.folder),
label: Text(folderName),
onPressed: () {
var note = editorState.getNote();
editor.moveNoteToFolderSelected(note);
},
)
],
mainAxisAlignment: MainAxisAlignment.center,
),
),
);
}
class StickyBottomAppBar extends StatelessWidget {
final BottomAppBar child;
StickyBottomAppBar({#required this.child});
#override
Widget build(BuildContext context) {
return Transform.translate(
offset: Offset(0.0, -1 * MediaQuery.of(context).viewInsets.bottom),
child: child,
);
}
}
I achieved this by a mix of two things I found separated in the web:
1 - Inside the Scaffold, I put other with only a bottomNavigationBar with a empty Container. For some reason, this trick push all my real bottomNavigationBar up to the top of the keyboard.
Scaffold(
bottomNavigationBar: Container(
height: 0,
),
body: Scaffold(
body: MyWidget(
But, I did not want all the content up, so I got that Package:
2 - I added flutter_keyboard_visibility: ^5.1.0 from
https://pub.dev/packages/flutter_keyboard_visibility
With this Package, you can do anything you want in response to keyboard visibility - is up to you. In my case, I made all content of my real bottomNavigationBar disappear except the textfield, which stay on the top of the keyboard:
[TextFormField] // dont go away,
//The others:
KeyboardVisibilityBuilder(builder: (context, visible) {
return Column(
children: [
visible
? SizedBox(
height: 0,
)
: OtherWidgets(
If you need some kind of button; you can do:
Scaffold(
bottomNavigationBar: bottomNavigationBar,
floatingActionButton: ExampleButton(
text: 'Hello',
),
body: body,
),
You can apply further customizations on the Floating Action Button using parameters in the Scaffold.
There is a simple way to do this if you want to really need to use the bottom navigation bar of the scaffold to put your widgets in rather than put it on a stack. Just wrap your scaffold with another scaffold and it should solve the problem.
return Scaffold(
body: Scaffold(
bottomNavigationBar: yourBottomNavigationBarWidget(),
body: yourBody(),
This works best especially when the height of your widget changes dynamically (because the text user types may introduce multiple lines) and you want the body to resize accordingly. A body in the stack, as suggested by many, will require a bottom padding to be visible over the text field and need to change dynamically as user types which is difficult to handle when you have multiple widgets sitting in and around the text field.

How to set multiline text using Text widget?

I'm trying to show a text in multiple lines, I mean like this:
"I am a text
and I finish here"
When I try to do that, I see a bar that says "Right Overflowed by 443 pixels".
I have this UI structure:
#override
Widget build(BuildContext context) {
return Card(
child: Scaffold(
body: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Column(
children: <Widget>[
Container(
padding: EdgeInsets.all(15.0),
child: Image.asset('images/place.png'),
)
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 15.0),
child: Text(
_placeCard.description,
style: TextStyle(),
softWrap: true
)
)
],
),
],
),
)
);
}
Where _placeCard.description is something like : "nce thethethe the the the 1500s, when an unknown printer took a galley of type and scrambled it to"
Could someone help me or give me any feedback?
Wrap your Text widget using a Flexible widget.
like,
//updated read: aziza comment
Flexible(//newly added
child: Container(
padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 15.0),
child: Text(
_placeCard.description,
style: TextStyle(),
softWrap: true
),
)
)
A simple example in below link:
https://gist.github.com/Blasanka/264510a0e7e5aaa151f02ada19fd466d
Update:
Above solution wraps the Text widget but in your question code snippet, the problem is you are using two Columns inside a Row and you havent added constraint. So, the easy solution to wrap those two Column widget using Flexible widgets.
like below,
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
child: Column(
//...
),
),
Flexible(
child: Column(
//...
),
),
],
),
Try wrapping your text widget in Expanded class and set it's flex factor. It will force the text to fit within the container.
Card(
color: kBoxColor,
child: Row(
children: [
Icon(Icons.description),
SizedBox(width:20.0),
Expanded(
flex: 30,
child: Text(
// Extremely long text,
style: kAnsTextStyle,
),
),
],
),
),

Flutter - Space Evenly in Column does not work as expected

Screenshot of the problem
I am trying to put elements in the red box by having even spaces between each other. (Like giving weight 1 to each of them). To do so, I put "mainAxisAlignment: MainAxisAlignment.spaceEvenly" in parent Column but it is not working.
Container(
margin: EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CachedNetworkImage(
imageUrl:
"https://image.tmdb.org/t/p/w500/${movieDetails
.posterPath}",
height: 120.0,
fit: BoxFit.fill),
Expanded(
child: Container(
margin: EdgeInsets.only(left: 8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //NOT WORKING!
children: <Widget>[
generateRow(
Strings.released, movieDetails.releaseDate),
generateRow(Strings.runtime,
movieDetails.runtime.toString()),
generateRow(Strings.budget,
movieDetails.budget.toString())
],
)))
],
)),
This is the code for movie image and the red box. I have created a Row which has 2 elements. First one is that image, second one is for red box.
Row generateRow(String key, String value) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[Text(key), Text(value)],
); }
My generateRow method
How can i solve this problem?
As you have given the height to the image is 120.0, can you do the same for the other Container child. By giving this, I was able to achieve what you want.
Code snippet:
Container(
margin: EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CachedNetworkImage(
imageUrl:
"https://image.tmdb.org/t/p/w500/${movieDetails
.posterPath}",
height: 120.0,
fit: BoxFit.fill),
Expanded(
child: Container(
height: 120.0 //added to fix
margin: EdgeInsets.only(left: 8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //NOT WORKING!
children: <Widget>[
generateRow(
Strings.released, movieDetails.releaseDate),
generateRow(Strings.runtime,
movieDetails.runtime.toString()),
generateRow(Strings.budget,
movieDetails.budget.toString())
],
)))
],
)),
Tips to debug:
I used Flutter Inspector to find the problem. Refer
Refer the image below. Even though we gave Expanded, it occupied just half the size of image. Here the size of Expanded is determined by child's size (which is almost half the image size).
try this :
new Container(
margin: EdgeInsets.only(bottom: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
CachedNetworkImage(
imageUrl:
"https://image.tmdb.org/t/p/w500/${movieDetails
.posterPath}",
height: 120.0,
fit: BoxFit.fill),
Expanded(
child: Container(
margin: EdgeInsets.only(left: 8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, //NOT WORKING!
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Text("Released : "),
new Text("25-07-2018 "),
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Text("Released : "),
new Text("25-07-2018 "),
],
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Text("Released : "),
new Text("25-07-2018 "),
],
),
],
)))
],
)),
Another way to achieve the result:
Expanded(
child: Center(
child: // your widget here,
),
)
This one should be the child of the Column, then it will work.
Try looking at this post:
Flutter Layout Row / Column - share width, expand height
Essentially, the image element in the Row makes the row expand in cross axis, but row's actual constraints are not modified. This is why Column's mainAxisAlignment: MainAxisAlignment.spaceEvenly is not working. It needs a parent constraint. And this is achieved with help of IntrinsicHeight. Wrapping Row widget with it will set row's constraints to the largest child's size (which is the image).

Resources