Display a built list of widgets in Dart - flutter

I've got a list of widgets I've built with a for in loop within a function but I'm unsure as how to display all the widgets as children of a column.
The function displayAllCards() builds the list, each widget starts with padding, i don't know if that helps or not.
Here's a very stripped down version of my unworking code.
The function to build a widget:
Widget displayCard(String bitCurrency) {
return Padding(
padding: EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 0),
child: Text("$bitCurrency"),
);
}
And then I built another function to create a list of widgets throwing in different bitCurrencies:
List displayAllCards() {
List<Widget> cards = [];
for (String bitCurrency in cryptoList) {
cards.add(displayCard(bitCurrency));
}
return cards;
}
And finally the output with the Flutter is where I'm dying.
body: Column(
children: <Widget>[
displayAllCards(),
],
),
I kinda know why it's not working, but I'm unsure how to make it correct.
I'm fairly new to Dart so please be gentle.

Just use spread operator (...)
body: Column(
children: <Widget>[
...displayAllCards(),
],
),

Related

Widget flickers and disappears when scrolling

I'm already losing sleep over this.
I'm trying to display a chart inside a ListView (for scrolling). For some reason the contents of the Card flickers when scrolling and randomly completely disappears (the Card itself stays visible though).
Any idea why would that happen?
(...) ListView (...)
children: [Row ( children: [buildChartBox()] )] (...)
Expanded buildChartBox() {
return Expanded(
child: Card(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
chartTitles(
title: 'Items',
subtitle: 'by value'),
SizedBox(
height: 300,
child: ValuesChart(data: calculateValues(items)))
],
),
],
),
),
),
);
}
Row chartTitles({String title = '', String subtitle = ''}) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: text_charttitle),
Text(subtitle, style: text_chartsubtitle),
],
)
],
);
}
Things tried:
Both of these were originally Stateless Widgets; I changed to simple
methods to simplify but it didn't change the weird behaviour.
Replacing the chartTitles return with an empty Container (i.e. removing the titles) does mitigate the issue. The chart then stays displayed but also flickers slightly.
Replacing the ListView with a SingleChildScrollView doesn't change anything.
EDIT: Code for the ValuesChart:
import 'package:fl_chart/fl_chart.dart';
class ValuesChart extends StatelessWidget {
final Map<String, int> data;
const ValuesChart({required this.data});
#override
Widget build(BuildContext context) {
return Container(
child: PieChart(
_theData(data),
));
}
}
Note I'm using a package called 'fl_chart'. _theData just returns various parameters for the chart, I don't think it's relevant.
Try to replace ListView with SingleChildScrollView
ListViews in flutter by default using what it is called in Android RecyclerView to efficiently use render resources.
If you are interested here an article
https://medium.com/1mgofficial/how-recyclerview-works-internally-71290de5d2c4

Flutter two widgets in body?

So my flutter app works fine, however I want to make some changes to it.
The 1st change I want to do is create a horizontal scroll widget that has images that are clickable that change stations.
But to do this I first need to join two widgets into one.
In my home_widget.dart file I have this code:
final List<Widget> _children = [TracksWidget(),
NewsWidget(),
AboutWidget()];
The code above changes the body section of the home_widget.dart section. But now what I want to do is add StationsWidget() to the bottom of the TrackWidget() - Note this widget refreshes every 30 seconds. So ideally I need to make sure it does not refresh with it.
So can a body have two widgets?
Full code of test.dart (which is where I am trying to add the widget)
import 'package:flutter/material.dart';
import 'trackswidget.dart';
class TestWidget extends StatelessWidget {
// final Color color;
// PlaceholderWidget(this.color);
#override
Widget build(BuildContext context) {
double c_width = MediaQuery.of(context).size.width;
return new Container (
padding: const EdgeInsets.all(16.0),
margin: const EdgeInsets.only(bottom: 0.0),
width: c_width,
child: new SingleChildScrollView(
child: new Column (
children: <Widget>[
Column(
children: <Widget>[
Child: TracksWidget()
],
),
Column(
children: <Widget>[
new Text('Advertise on ',style: TextStyle(color: Colors.black, fontSize: 20.0),),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children:
),
],
),
]
),
),
);
}
}
The error I am getting is
'Widget' is from 'package:flutter/src/widgets/framework.dart' ('/C:/src/flutter/packages/flutter/lib/src/widgets/framework.dart').
Try changing the type of the parameter, or casting the argument to 'List'.
children: TracksWidget,
Just so you all know what I am trying to achieve. We redesigned our iOS Swift app and now want our flutter app to match.
Strictly speaking, no, the body takes exactly one Widget. You could say it takes none if you pass null, but you cannot pass more than one.
However, there are widgets that group other widgets. Your one body widget could as well be a Row and that row can have multiple child widgets.
You already did that in your title.
A nice graphical representation can be found in the documentation.

Responsive wrapping rows with specific widths and alignments

I want my flutter app to look a certain way when the phone is tilted vs when it's held normally.
I have created a solution for each state but I can't figure out a solution that works for both at once.
So my question is: how can I achieve the following with one codebase?
- and if it is not easily possible: how can I make my app dynamically decide which layout to use?
Here's a minified example of my app (my generateList* methods are shown below):
void main(List<String> arguments) async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Test",
home: Scaffold(
body: ListView(
//children: generateListTilted(),
//or
children: generateListNotTilted(),
),
),
);
}
}
I have rows with two fields of information, the date and the content.
The date does not always have the exact width 'cause the months are spelled out, but it's similar.
The content always has the same length.
Case: phone tilted/wide screen
If there is enough space for both fields in one line, each row should look like it has two colums - the first one having the width of the largest date field, and the second one just filling out the rest of the space and being centered. I didn't know how to adjust the width automatically to the widest date so I just set the flex property as a workaround:
List<Widget> generateListTilted() {
var sameSizeContent = "TEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEST";
var slightlyVariableLengthDates = ["August, 21 2019", "May, 1 2019"];
List<Widget> listOfRows = [];
for (var i = 0; i < slightlyVariableLengthDates.length; i++) {
listOfRows.add(
Container(
padding: const EdgeInsets.all(2.0),
child: Row(
children: <Widget>[
Expanded(
flex: 3,
child: Text(
slightlyVariableLengthDates[i],
textAlign: TextAlign.right,
)),
Expanded(
flex: 7,
child: Text(
sameSizeContent,
textAlign: TextAlign.center,
),
)
],
),
),
);
}
return listOfRows;
}
Case: phone not tilted/small screen
If the date and content do not fit in one line, they should wrap and the date should be on the top left - but again have the width of the longest date and right alignment (I was not able to achieve this so I edited the screenshot to make it clear).
The content should be centered again:
List<Widget> generateListNotTilted() {
var sameSizeContent = "TEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEST";
var slightlyVariableLengthDates = ["August, 21 2019", "May, 1 2019"];
List<Widget> listOfRows = [];
for (var i = 0; i < slightlyVariableLengthDates.length; i++) {
listOfRows.add(
Container(
padding: const EdgeInsets.all(2.0),
child: Row(
children: <Widget>[
Expanded(
child: Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Text(
slightlyVariableLengthDates[i],
),
Center(child: Text(sameSizeContent))
],
),
),
],
),
),
);
}
return listOfRows;
}
I want my flutter app to look a certain way when the phone is tilted
vs when it's held normally. I have created a solution for each state
but I can't figure out a solution that works for both at once.
Use MediaQuery to know about your current screen orientation and other device related information.
Example Code:
Container(
alignment: Alignment.center,
child:
(MediaQuery.of(context).orientation == Orientation.portrait)
Text("Portrait")
:
Text("Landscape")
)
Note: I have used ternary operator outside the Text widget to show that ternary operator can be used almost anywhere(Widget,String,parameter values), where we just need to apply small logical UI changes.
If you're looking at making your UI responsive, please checkout the answer to a similar question.

Flutter equivalent of layout_gravity="bottom"

I am trying to render a dribbble sample.
In normal android using XML, I can make any part stick to any side of another view. If I were using ConstraintLayout, I could make the bottom part stick to the bottom of the parent and let the top part expand to available height.
The design on both emulators is Flutter code.
On larger screens, there is some empty space on the bottom. How do I remove that?
Currently, I am using Flexible with flex values but it doesn't look right. How to make this reactive?. Is the use of Flexible correct?
The code can found here on pastebin
There is nothing like android:layout_gravity in Flutter, however you can pretty much achieve anything in Flutter. So, here you can use use Spacer(). Like:
return Column(
children: <Widget>[
Spacer(),
Align(alignment: Alignment.centerRight, child: Text("123")),
YourButtonsWidget(),
],
);
try to change CalculatorPrototype's build function like this
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisSize: MainAxisSize.min, // actually this line and the next one doesn't needed
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: display,
),
Container(
child: keypad,
),
],
),
);
}

How to Implement Flutter Functions

With reference to a Stack Ordering solution (Flutter - changing a Stack Order)
Summary - I have a stack of widgets I want to reorder. The solution is to use functions to recreate the correct order of widgets. In the example linked to above works (great!). However, the example widgets were small - no issue to simply repeat the same code to re-order.
My real world example - the stack of widgets is reasonably complex and I have refactored into functions to reuse between the stack order functions:
Let's say the original stack has this as one of the widgets in the stack:
final statusMessage = new Container(
padding: new EdgeInsets.all(3.0),
margin: new EdgeInsets.only(bottom: 0.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
new Text(
statusText,
style: themeData.textTheme.subhead,
),
],
),
alignment: Alignment.topCenter);
I have been declaring all these widgets in the single Widget build class.
The functions to reorder the stacks are outside of this build function. An example:
void swapStackChildren() {
setState(() {
stackChildren = [
Positioned.fill(
child: statusMessage,
key: GlobalKey(),
),
Positioned.fill(
child: widget2, // a complex widget
key: GlobalKey(),
),
etc....
];
});
}
Ideally, I need a way to (forward) reference the widgets in swapStackChildren that are declared in the build method or a way to reference 'context' outside of the build method so I can reference themeData.
Perhaps it is my lack of understanding of the structure/layout of a page? I have only one Widget build class where I am declaring all my widgets (header, content area, buttons, etc) and these cannot be referenced by functions in the preceding code.