When I Wrap a chips list, how can I limit the area (the wrap area) to 2 lines max? - flutter

I have a list that I want to show in chips and organize in a Wrap widget.
However, no matter what the list.length is (or the length of a single string inside the list), I want to build only 2 lines of the Wrap area.
Here is my code:
class TagsView extends StatelessWidget {
#override
Widget build(BuildContext context) {
List<Widget> list = List<Widget>.from(
{"bla1", "bla2", "bla3", "bla4", "bla5", "bla6", "bla7","bla8", "bla9", "bla10", "bla11", "bla12", "bla13", "bla14"}
.map((tag) => Chip(
label: Text(
tag,
),
))
.toList());
return Wrap(
verticalDirection: VerticalDirection.down,
spacing: 5.0,
runSpacing: 10.0,
children: list,
);
}
}
and here are Examples for the unwanted code (the first screenshot is the result of the code above)
A good result will look like this:

You can put it in a Container and limit the height.
It will always show the first two lines.
return Container(
height: 100,
child: Wrap(
verticalDirection: VerticalDirection.down,
spacing: 5.0,
runSpacing: 10.0,
children: list,
),
);

Probably too late, but you can use the take method.
List<Widget> list = List<Widget>.from({
"bla1",
"bla2",
"bla3",
"bla4",
"bla5",
"bla6",
"bla7",
"bla8",
"bla9",
"bla10",
"bla11",
"bla12",
"bla13",
"bla14"
}
.take(2)
.map((tag) => Chip(
label: Text(
tag,
),
))
.toList());

Related

Flutter - Update items in a ListView

I'm trying to change the order of widgets in a ListView as follows:
Widgets List
List<Widget> widgets = [const Text("Widget 1"), const Text("Widget 2")];
ListView
ListView(children: widgets),
Text("$widgets")
Function
() {
widgets.shuffle();
setState(() {
widgets = widgets;
});
}
This way the order of widgets is changed in the TEXT but not in the list as I intended.
Any idea?
First solution: Add Key to List ListView like this:
ListView(
key: UniqueKey(),// <--- add this
children: widgets,
),
also in your Function you don't need to pass widgets again:
() {
widgets.shuffle();
setState(() {});
}
Second solution: you can use SingleChildScrollView and Column like this:
Padding(
padding: const EdgeInsets.all(20.0),
child: SizedBox(
height: 50,
width: 100,
child: SingleChildScrollView(
child: Column(
children: widgets,
),
),
),
),

Columns+Rows vs Stack for static sized grid?

I have a list of widgets (from a list of objects that have an x and y coordinate value) of the same size I want display in a grid arrangement, the size and placement wont change.
My initial thought is to use 2 for loops for the columns and rows and pass the widgets as children accordingly.
But would a Stack widget or CustomMultiChildLayout be more performant and suited for this? Given that columns and rows are made to be more dynamically sized and I don't need that functionality.
Edit: Image, literally just a grid of tiles at the moment. It's currently using loops of columns+rows. Yes I will be flipping the Y around to start at the bottom corner.
You can use a gridview to create this layout
class MyHomePage extends StatelessWidget{
#override
Widget build(BuildContext context){
return Scaffold(
body: GridView.count(
crossAxisCount: 15,
children: List.generate(225, (index) {
return GridTile(
child: Container(
height: 50,
width: 50,
color: Colors.blue.shade200,
child: Center(
child: Text('$index'),
)
),
);
}),
),
);
}
}
Or In a wrap
Wrap(
children: List.generate(225, (index) => Container( width: 20, height: 20, child: Text("$index")))
)

How to display a screen which contains of an Icon on top half and ListView on bottom half?

I want to display a mock-up streaming screen like this:
Top half is the video player (showing the speaker), and bottom half is a ListView displaying participants/subscribers list.
Here's my code:
import 'package:flutter/material.dart';
import 'common.dart';
class StreamingView extends StatelessWidget {
// Display a Participant item
Widget getParticipantView(Participant item) {
return Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
item.name,
style: TextStyle(fontSize: 14, color: Colors.black54),
),
),
Expanded(
child: CircleAvatar(backgroundColor: Colors.blue),
),
],
));
}
// Display the participants list on a ListView
Widget getParticipantsListView(List<Participant> participantsList){
//#override
// Widget build(BuildContext context) {
return Container (
//Expanded()
height: 40,
child: ListView.builder(
itemCount: participantsList.length,
itemBuilder: (context, index){
return getParticipantView(participantsList[index]);
}
)
);
//}
}
#override
Widget build(context) {
List<Participant> theList = [
Participant(name: "Jack", description:"Away"),
Participant(name:"Paul", description:"Available"),
Participant(name:"Clive", description:"Available"),
Participant(name:"Frank", description:"Available")
];
return Scaffold(
appBar: AppBar(),
body: Container(
padding: EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Image.asset('assets/generic_portrait.jpg'),
Expanded(
flex: 1,
child: getParticipantsListView(theList)
),
],
)),
floatingActionButton: FloatingActionButton(
onPressed: () async {
print("The button is clicked...");
},
child: Icon(Icons.video_call)));
}
}
I ran it, and the result is this:
The speaker can be seen, but the participants list isn't. Turns out there's an exception:
══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY
╞═════════════════════════════════════════════════════════ The
following assertion was thrown during performLayout(): RenderFlex
children have non-zero flex but incoming height constraints are
unbounded. When a column is in a parent that does not provide a finite
height constraint, for example if it is in a vertical scrollable, it
will try to shrink-wrap its children along the vertical axis. Setting
a flex on a child (e.g. using Expanded) indicates that the child is to
expand to fill the remaining space in the vertical direction. These
two directives are mutually exclusive. If a parent is to shrink-wrap
its child, the child cannot simultaneously expand to fit its parent.
Consider setting mainAxisSize to MainAxisSize.min and using
FlexFit.loose fits for the flexible children (using Flexible rather
than Expanded). This will allow the flexible children to size
themselves to less than the infinite remaining space they would
otherwise be forced to take, and then will cause the RenderFlex to
shrink-wrap the children rather than expanding to fit the maximum
constraints provided by the parent. ... ... The relevant error-causing
widget was: Column
file:///C:/Users/anta40/Flutter/streamingtest/streaming.dart:11:16
That refers to child: Column( inside Widget getParticipantView().
How to fix this?
you can use stack , the parent maybe use column after that the stack will be the first , after that use a listview which can hold all the participants
Have you tried using Shrink-wrap in ListView.builder and remove the container with Static height.
The hight is unbound because you're using Expanded widget in the column. Remove the Expanded widget that is wrapping the CircleAvatar. Here's your code:
// Display a Participant item
Widget getParticipantView(Participant item) {
return Container(
padding: EdgeInsets.all(10.0),
child: Column(
children: [
Align(
alignment: Alignment.centerLeft,
child: Text(
item.name,
style: TextStyle(fontSize: 14, color: Colors.black54),
),
),
CircleAvatar(backgroundColor: Colors.blue),
],
));
}

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.

How to iterate over list to incorporate it in a wrap widget?

I am trying to restrict the items(Containers) in the Row to 8 and if there are more items, they should be wrapped. I have a list of Containers but I can not use listView as children of Wrap since listView scrolls. Is there any way to get this layout fixed?
I have tried using for loop but as it hits return for the first time, it gets out of loop.
I have tried gridView instead of wrap but it doesn't give me the result as gridView is scrollable.
Expanded(
flex: 4,
child: Wrap(
direction: Axis.horizontal,
spacing: 0.5,
runSpacing: 0.5,
crossAxisAlignment: WrapCrossAlignment.center,
children: <Widget>[
// I want something that works like following line
//Container(child: kids1)
//currently I can get results with following code
kids1[1],
kids1[2],
kids1[3], kids1[4], kids1[5], kids1[6],
kids1[7], kids1[8], kids1[9], kids1[10],
kids1[11]
],
),
),
kids is a list of Containers
Why don't you create the list of children before the return of the build function :
#override
Widget build(BuildContext context) {
List<Widget> children = List.generate(myContainerList.length, (e) => myContainerList[e]);
return Wrap(
children: children,
);
}