Vertical and Horizontal Coordinated Scrolling of Independent Lists - flutter

I have joined tables of data that I need to scroll together on both horizontal and vertical axis, with heading First Row that should not scroll with vertical data, but should scroll with horizontal.
You can see from my video that my simplified example below will scroll as desired vertically, but the rows, being independent do not scroll horizontally together as needed. The question is how to scroll each independent list horizontally together without losing the vertical functionality. The number of rows and columns is variable and can be quite large. My example code below is simplified to illustrate the behavior.
The below is a complete project example that can be cut and pasted into a dartpad flutter project or just click here: https://dartpad.dev/?id=6c4ea40ceee87ce9de4bcfe38ba0b750
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: MyWidget(),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
List listDates = ['Jan', 'Feb', 'Mar', 'Apr'];
Map<String, List> all = {
'Todd': [1,2,3,4],
'Mary': [5,6,7,8],
'Henry': [9,10,11,12],
};
List<String> names = [];
all.forEach((key,value) {
names.add(key);
});
return Column(
children: [
SizedBox(
height: 200,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const SizedBox(
height: 200,
width: 200,
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: listDates.length,
itemBuilder: (context, index) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 200,
child: Center(
child: Text(
listDates[index],
style: const TextStyle(
fontWeight: FontWeight.w600,
),
maxLines: 1,
textAlign: TextAlign.center,
),
),
),
],
);
},),
),
],
),
),
Expanded(
child: ListView.builder(
itemCount: 3,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
color: index.isOdd ? Colors.blue.withOpacity(.2) : Colors.grey.withOpacity(.2),
),
child: SizedBox(
height: 200,
width: double.infinity,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
SizedBox(
width: 200,
height: 200,
child: Padding(
padding: const EdgeInsets.all(4.0),
child: Text(
names[index],
style: const TextStyle(
fontWeight: FontWeight.w500,
),
),
),
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: listDates.length,
itemBuilder: (context, index2) {
List ints = all[names[index]]!;
return SizedBox(
width: 200,
child: Center(
child: Text(
ints[index2].toString(),
style: const TextStyle(
fontWeight: FontWeight.w600,
),
maxLines: 1,
textAlign: TextAlign.center,
),
),
);
},
),
),
],
),
),
);
},
),),
],
);
}
}

Related

flutter Specify height of card in listview.builder

I want the cards built in a listview.builder, to have a height of 150.
What currently happens:
Currently, with my code, here's what gets built. Instead of the default height, I want to explicitly set my own card height, say, 150
What I have tried:
Isn't using SizedBox enough to get the height I want in a listview?
class GamesListState extends State<GamesList> {
#override
Widget build(BuildContext context) {
return MyScaffold(
body: Container(
padding: const EdgeInsets.symmetric(vertical: 18, horizontal: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 32),
const MyHeaderTitle(title: 'Games'),
const SizedBox(height: 40),
Flexible(
child: ListView.builder(
itemCount: list.length,
prototypeItem: ListTile(
title: Text(list.first.values.first),
),
itemBuilder: (context, index) {
return Card(
elevation: 5,
child: SizedBox(
height: 150,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Image.asset('assets/images/logo.png'),
const Text(
'Game name',
style: TextStyle(
fontSize: 10, fontWeight: FontWeight.w700),
),
const Icon(Icons.keyboard_arrow_right)
],
),
),
);
},
)),
],
),
),
);
}
}
Will appreciate any insights as to what I'm doing wrong.
Specify the height of prototypeItem of listView.builder by wrapping it with SizedBox
prototypeItem: ListTile(
title: SizedBox(height: 150, child: Text(list.first.values.first)),
),

Flutter: Errors when wrapping Layoutbuilder and Text in Column

I currently have a listview with an alphabet scroller on the side. I'm trying to add a searchbox to the top, but whenever I wrap something in a column, I get errors.
Using the current code, ListView inside Stack is throwing Vertical viewport was given unbounded height.
When I remove the column and Text('TestString'), my code works fine. I have tried adding an Expandable around the ListView.Builder but this also doesn't seem to solve it.
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
return Scaffold(
appBar: AppBar(
title: Text(widget.title,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
fontWeight: FontWeight.bold)),
centerTitle: true,
),
body: Column(
children: [
Text('TestString'),
new LayoutBuilder(
builder: (context, constraints) {
return new Stack(children: [
//Causes the current issue
ListView.builder(
itemCount: exampleList.length,
controller: _controller,
itemExtent: _itemsizeheight,
itemBuilder: (context, position) {
return Padding(
padding: const EdgeInsets.only(right: 32.0),
child: Card(
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
exampleList[position],
style: TextStyle(fontSize: 20.0),
),
),
));
},
),
Positioned(
right: _marginRight,
top: _offsetContainer,
child: _getSpeechBubble()),
Align(
alignment: Alignment.centerRight,
child: GestureDetector(
onTapDown: (details) {
_onTapDown(details);
},
child: GestureDetector(
onVerticalDragUpdate: _onVerticalDragUpdate,
onVerticalDragStart: _onVerticalDragStart,
onVerticalDragEnd: (details) {
setState(() {
isPressed = false;
});
},
child: Container(
//height: 20.0 * 26,
color: Colors.transparent,
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: []..addAll(
new List.generate(_alphabet.length,
(index) => _getAlphabetItem(index)),
),
),
),
),
),
),
]);
},
),
],
),
);
}
_getSpeechBubble() {
return isPressed
? new SpeechBubble(
nipLocation: NipLocation.RIGHT,
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Container(
width: 30,
child: Center(
child: Text(
"${_text ?? "${_alphabet.first}"}",
style: TextStyle(
color: Colors.white,
fontSize: 18.0,
),
),
),
),
],
),
)
: SizedBox.shrink();
}
ValueGetter? callback(int value) {}
_getAlphabetItem(int index) {
return new Expanded(
child: new Container(
width: 40,
height: 20,
alignment: Alignment.center,
child: new Text(
_alphabet[index],
style: (index == posSelected)
? new TextStyle(fontSize: 16, fontWeight: FontWeight.w700)
: new TextStyle(fontSize: 12, fontWeight: FontWeight.w400),
),
),
);
}
You can wrap your LayoutBuilder() with Expanded() like this and it won't show an error.
return Container(
child: Column(
children: [
Text("Header"),
Expanded(
child: ListView.builder(
itemCount:50,
itemBuilder: (BuildContext context, int index) {
return Text("List Item $index");
},
),
),
Text("Footer"),
],
),
);
You can try the code here

How to get two rows in ListView.separated

I wanted to achieve the following output but instead of one row in a column, I want to show two rows in a column using ListView.separated. How can I get it? ListView.separated does not have any option to display 2 rows.
Scaffold(
body: ListView.separated(
itemBuilder: (context, position) {
return Container(
height: 40.0,
color: Colors.white,
child: Text('Your text goes here'),
);
},
separatorBuilder: (context, position) {
return Container(
color: Colors.red,
child: Text('Divider'),
);
},
itemCount: 20,
),
));
To achieve this, you can use the Row widget. In order to expand the Text widgets, you can wrap them with Expanded.
Full working example, based on your code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView.separated(
itemBuilder: (context, position) {
return Container(
height: 40.0,
color: Colors.white,
child: Text('Your text goes here'),
);
},
separatorBuilder: (context, position) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Text(
'Divider 1',
textAlign: TextAlign.center,
),
),
),
Expanded(
child: Container(
color: Colors.red,
child: Text(
'Divider 2',
textAlign: TextAlign.center,
),
),
),
],
);
},
itemCount: 20,
),
),
);
}
}

Defining the width and height in a container nested in row in flutter is leaving a space at the end of the row

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class TabStories extends StatelessWidget {
#override
Widget build(BuildContext context) {
final title = 'Grid List';
return ListView(
children: List.generate(100, (index) {
return Card(
child: Row(
children: <Widget>[
Flexible(
child: Container(
width: 80,
height: 80,
),
),
Flexible(
child: Text(
'hi i am sfbskdbvkjsdk ksfkj sd hsdvm d dsj s bjksdvjd '),
)
],
),
elevation: 5,
);
}),
);
}
}
dont want the empty space at the end of each row. kindly help
Trying to generate a row with a container containing the image and then a text description of the same. However, getting the empty space at the end.
ListView(
shrinkWrap: true,
children: List.generate(5, (index) {
return Card(
child: Row(
children: <Widget>[
Container(
width: 100,
height: 100,
),
Flexible(
child: Text(
'hi i am sfbskdbvkjsdk ksfkj sd hsdvm d dsj s bjksdvjd ',
style: TextStyle(fontSize: 17),),
)
],
),
elevation: 5,
);
}),
),

Handle listview item height?

So i have this script which is build a listview
class NewProductsLists extends StatelessWidget {
final List<NewProducts> newlist;
NewProductsLists({Key key, this.newlist}) : super(key: key);
final formatCurrency =
new NumberFormat.simpleCurrency(locale: "id", decimalDigits: 2);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
itemCount: newlist.length,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
print("Product detail");
},
child: Card(
child: Container(
width: MediaQuery.of(context).size.width * 0.50,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.network(
Configuration.url +
"assets/app_assets/" +
newlist[index].productImage,
width: 90,
height: 90,
filterQuality: FilterQuality.low),
ListTile(
title: Center(
child: Text(
newlist[index].productName,
style: TextStyle(fontSize: 18),
)),
subtitle: Center(
child: Text(
formatCurrency.format(
int.parse(newlist[index].productPrice)),
style: TextStyle(color: Colors.red, fontSize: 15),
)),
),
],
)),
),
);
}));
}
}
and the result looks like this
[
As you can see the card is expanding so hard. I know it is because the Expanded widget. Is it possible to make the card wrap_content ?
For horizontal list view needs fixed height if its not going to be vertical scrollable view you can use Expanded widget with varying flex to get it working.
Working build widget by using expanded widget.
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
centerTitle: false,
title: const Text('November'),
),
body: new Container(
child: Column(
children: <Widget>[
new Expanded(flex: 1,child: new Container(color: Colors.grey[300],),),
Expanded(flex: 2,
child: ListView.builder(
itemCount: 10,
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
print("Product detail");
},
child: Card(
child: Container(
width: MediaQuery.of(context).size.width * 0.50,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Image.network(
'https://homepages.cae.wisc.edu/~ece533/images/watch.png',
width: 90,
height: 90,
filterQuality: FilterQuality.low),
ListTile(
title: Center(
child: Text(
'item Name ${index}',
style: TextStyle(fontSize: 18),
)),
subtitle: Center(
child: Text(
'\$10',
style: TextStyle(
color: Colors.red, fontSize: 15),
)),
),
],
)),
),
);
}),
),
new Expanded(flex: 3,child: new Container(color: Colors.amber[100],),),
],
)));
}
Result screen
Let me know if it suits your requirement.