looping on list to display positioned behind each other - dart

i have a list and am looping on it and display a positioned container for each item .. and they are behind each other ..
am doing this:
List<Widget> createQues(){
data = questionsList;
double bottom = 190.0;
List<Widget> children = <Widget>[];
for (var q in data){
bottom += 10.0;
children.add(new Positioned(
bottom: bottom,
child: new Container(
width: 100.0,
height: 80.0,
decoration: new BoxDecoration(
borderRadius: BorderRadius.all(const Radius.circular(20.0)),
color: Colors.white,
boxShadow: [
new BoxShadow(
color: Color(0xffECECEC),
blurRadius: 20.0,
),
],
),
child: new Text(q.title),
)
)
);
}
return children;
}
and then called it like this:
new Stack(
alignment: AlignmentDirectional.center,
children: createQues()
)
my problem is that the first item in my list is actully displayed the last in the stack .. i want the first item in the list to be on the top of the stack and the others sorted behind it ..
for example:
lets say i have 2 elements in the list :
as shown i will always got item 2 on top of item 1.. how to make it sorted so item 1, item 2, item 3 ... not the reverse on the stack?

Can't you just reverse the questions list before using it?
Like, you could try changing data = questionsList to data = questionsList.reversed.

Related

an empty widget is created when trying to iterate through a list and create widget in flutter

I am trying to iterate through a list and render multiple widgets in flutter. my list has two items. the weird thing is that the two items get built but an emty space between them gets build too.
here is my code:
Column(
children: state.homePageData.categories
.map((item) => Container(
height: 100,
width: double.infinity,
child: Column(
children: <Widget>[
Image.network(
baseUrl + item.img.toString(),
height: 100,
width: 100,
),
],
)))
.toList(),
)
That's not an empty widget, but the image itself doesn't fill the container's height. Try adding fit property to the image widget. You can find more on FitBox enum here

Warp text on a row with an input

I have a situation where I need to wrap text with an input in Flutter. An example: 'The cat goes <TextField>, the dog goes bark.'
I'm using the Row class to format it this way, however, the row class doesn't wrap text.
Widget _buildQuestionText(String sentence) {
List splitSentence = sentence.split('\$guess');
return new Container(
child: Row(
children: <Widget>[
new Text(splitSentence[0]),
new Expanded(child: new TextField()),
new Text(splitSentence[1]),
]
),
);
}
Which creates:
I have looked at using the Flex class but was unable to achieve the format I wanted. How can I achieve text wrapping with an input in the middle of text?
Wrap accepts a list of children that wraps while row accepts a list of children that do not wrap.
return new Container(
child: new Wrap(
spacing: 8.0, // gap between adjacent chips
runSpacing: 4.0, // gap between lines
children: [
new Text(splitSentence[0]),
new Container(
width: 100.0,
child: new TextField(
style: new TextStyle(
fontSize: 16.0,
color: Colors.black
)
)
),
new Text(splitSentence[1]),
],
)
);

Flutter - Showing suggestion list on top of other widgets

I am developing a screen where I have to show suggestions list below the textfield.
I want to achieve this
I have developed this so far
Following code shows textfield with suggestions in a list.
#override
Widget build(BuildContext context) {
final header = new Container(
height: 39.0,
padding: const EdgeInsets.only(left: 16.0, right: 2.0),
decoration: _textFieldBorderDecoration,
child: new Row(
children: <Widget>[
new Expanded(
child: new TextField(
maxLines: 1,
controller: _controller,
style: _textFieldTextStyle,
decoration:
const InputDecoration.collapsed(hintText: 'Enter location'),
onChanged: (v) {
_onTextChanged.add(v);
if (widget.onStartTyping != null) {
widget.onStartTyping();
}
},
),
),
new Container(
height: 32.0,
width: 32.0,
child: new InkWell(
child: new Icon(
Icons.clear,
size: 20.0,
color: const Color(0xFF7C7C7C),
),
borderRadius: new BorderRadius.circular(35.0),
onTap: (){
setState(() {
_controller.clear();
_places = [];
if (widget.onClearPressed != null) {
widget.onClearPressed();
}
});
},
),
),
],
),
);
if (_places.length > 0) {
final body = new Material(
elevation: 8.0,
child: new SingleChildScrollView(
child: new ListBody(
children: _places.map((p) {
return new InkWell(
child: new Container(
height: 38.0,
padding: const EdgeInsets.only(left: 16.0, right: 16.0),
alignment: Alignment.centerLeft,
decoration: _suggestionBorderDecoration,
child: new Text(
p.formattedAddress,
overflow: TextOverflow.ellipsis,
maxLines: 1,
style: _suggestionTextStyle,
),
),
onTap: () {
_getPlaceDetail(p);
},
);
}).toList(growable: false),
),
),
);
return new Container(
child: new Column(
children: <Widget>[header, body],
),
);
} else {
return new Container(
child: new Column(
children: <Widget>[header],
),
);
}
}
Header(Textfield) and body(Suggestions List - SingleChildScrollView with ListBody) is wrapped inside the Column widget, and column expands based on the total height of the children.
Now the problem is as Column expands, layout system pushes other widgets on screen to the bottom. But I want other widgets to stay on their positions but suggestion list starts to appear on top of other widgets.
How can I show suggestions list on top of other widgets? And the suggestions list is dynamic, as user types I call the Google Places API and update the suggestions list.
I have seen there is showMenu<T>() method with RelativeRect positions but it doesn't fulfills my purpose, my suggestion list is dynamic(changing based on user input) and the styling for each item I have is different from what PopupMenuItem provides.
There is one possibility I can think of using Stack widget as root widget of this screen and arrange everything by absolute position and I put suggestion list as a last child of the stack children list. But it is not the right solution I believe.
What other possibilities I need to look into? What other Widgets can be used here in this use-case?
And again use-case is simple, overlaying suggestion list on other widgets on the screen and when user tap any of the item from the list then hiding this overlaid suggestion list.
The reason why your autocomplete list pushes down the widgets below it is because the List is being expanded on the Container. You can use Flutter's Autocomplete widget and it should inflate the autocomplete list over other widgets.
var fruits = ['Apple', 'Banana', 'Mango', 'Orange'];
_autoCompleteTextField() {
return Autocomplete(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return fruits.where((String option) {
return option
.toLowerCase()
.contains(textEditingValue.text.toLowerCase());
});
},
onSelected: (String selection) {
debugPrint('You just selected $selection');
},
);
}

Flutter position fixed equivalent

Is it possible to fix an object in the screen that stays fixed regardless of scrolling?
Something similar to CSS position fixed.
You can absolutely position a child of a Stack widget using the Positioned widget.
The minimal example below places the red box above the list view, by placing the child in a Positioned widget after the ListView in the Stack's children.
List<String> todos = [...];
return new Stack(
children: <Widget>[
new ListView(
children: todos
.map((todo) => new ListTile(title: new Text(todo)))
.toList(),
),
new Positioned(
left: 30.0,
top: 30.0,
child: new Container(
width: 100.0,
height: 80.0,
decoration: new BoxDecoration(color: Colors.red),
child: new Text('hello'),
)
),
],
);
And here it is inside of a Scaffold body. If you add more items you'll find that the list scrolls without moving the red box.
You could use Positioned widget in a Stack Widget with AspectRatio widget and use the % distance like the below code.
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; //get the screen size
List<String> todos = [...];
//the below if to get the aspect ratio of the screen i am using the app only in landscape
//if you need to use it in portrait you should add the sizes below
if((size.width / size.height) > 1.76){
aspect = 16 / 9;
}else if((size.width / size.height) < 1.77 && (size.width / size.height) >= 1.6){
aspect = 16 / 10;
}else{
aspect = 4 /3;
}
return new Scaffold(
body: new Center(
//layoutBuilder i can use the constraints to get the width and height of the screen
child: new LayoutBuilder(builder: (context, constraints) {
return new AspectRatio(
aspectRatio: aspect,
child: new Column(
children: <Widget>[
new ListView(
children: todos
.map((todo) => new ListTile(title: new Text(todo)))
.toList(),
),
new Positioned(
//constraints.biggest.height to get the height
// * .05 to put the position top: 5%
top: constraints.biggest.height * .05,
left: constraints.biggest.width * .30,
child: new Container(
width: 100.0,
height: 80.0,
decoration: new BoxDecoration(color: Colors.red),
child: new Text('hello'),
),
),
],
),
),
}),
),
);
}
}
Hope it will help you....
I prefer this solution:
Stack(
children: [
Column(
children: [
Container(...),
Container(...),
]
),
Positioned(top:50, child: Card(...))
]
)
Widget build(BuildContext context) {
return Column(
children: [
Container(
// covers 20% of total height
height: 200,
child: Stack(
children: [
Container(
height: 300,
decoration: BoxDecoration(
color: Colors.red,
),
),
Positioned(
bottom: 0,
left: 0,
width: 100,
height: 100,
child: Container(
height: 54,
decoration: BoxDecoration(
color: Colors.blue,
),
),
)
],
),
),
],
);
}
Adding a width and height to your Positioned widget will make it appear if you want to use top/left/bottom/right

Flutter - Combine dynamically generated elements with hard-coded ones

I'm basically creating a game where a grid is getting generated dynamically. It creates the tiles, adds them to a list and uses that list as an argument for the children parameter. What I find difficult however is combining it with fixed widgets.
Let's say on top of everything, I want a text element. The problem I now encounter is that if I assign my dynamically generated content like this:
...
children: mycontent,
...
then I have nowhere to put my hard coded widgets. I hope you know what I mean. Until now, I have solved it by creating a larget list and copying the dynamically generated elements over, and afterwards adding my hard-coded widgets:
Widget buildTile(int counter) {
return new GestureDetector(
onTap: (){
setState((){
toggleColor(counter);
});
},
child: new Container(
color: colors[counter],
foregroundDecoration: new BoxDecoration(
border: new Border(),
),
width: 75.0,
height: 75.0,
margin: new EdgeInsets.all(2.0),
)
);
}
List<Widget> buildGrid(){
Map dimensions = {"width" : 4, "height" : 6};
List<Widget> grid = new List<Widget>(dimensions["height"]);
List<Widget> tiles = [];
int counter = 0;
for (int i = 0; i < dimensions["height"]; i++){
tiles = [];
for (int j = 0; j < dimensions["width"]; j++){
tiles.add(buildTile(counter));
counter++;
}
grid[i] = new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: tiles,
);
}
return grid;
}
List<Widget> copyElements(List<Widget> from){
List<Widget> to = [];
for (int i = 0; i < from.length; i++){
to.add(from[i]);
}
return to;
}
List<Widget> buildPlayground(List<Widget> grid){
List<Widget> playground = [];
playground = copyElements(grid);
playground.add(new Padding(
padding: new EdgeInsets.all(20.0),
child: new RaisedButton(
color: Colors.purple,
child: new Container(
width: 100.0,
child: new Center(
child: new Text("Done", style: new TextStyle(fontSize: 20.0)),
),
),
onPressed: (){
}
),
));
return playground;
}
#override
build(BuildContext context){
return new Scaffold(
appBar: new AppBar(
title: new Text("Game"),
),
body: new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: buildPlayground(buildGrid()),
)
),
);
}
It kinda works, but is very tedious as soon as I figure out that I want to add another hard coded widget. Any suggestions for how I can address this problem?
Thanks
I guess this is the way to go, however you could use the GridView widget, and you could create a TileWidget instead of you buildTile function. Using GridView should clean your code, but what do you mean by hard-coded widgets ?
You can combine the accepted answer from this question and use the spread operator, like what's below, to combine a list with another list or with singular items.
List<Widget> generatedWidgets = generateWidgetList();
List<Widget> hardCodedWidgets = hardCodeWidgetList();
Widget singleHardCodedWidget = Container(
child: Text('some text'),
);
combinedList = [...generatedWidgets, ...hardCodedWidgets, singleHardCodedWidget];

Resources