I am getting an error when I wrap my container in the column widget. I need 2 containers in a column but when I wrap it in column widget it's showing this error
'package:flutter/src/rendering/box.dart':
Failed assertion: line 1694 pos 12: 'hasSize'
Showing this in Column line error
Here is my code
class _PlaceListState extends State<PlaceList> {
final List _places = [
{'name': 'Hunza', 'where': 'Gilgit Baltistan'},
{'name': 'Skardu' ,'where': 'Gilgit Baltistan'},
{'name': 'Murree', 'where': 'Gilgit Baltistan'},
];
#override
Widget build(BuildContext context) {
return Column(children: <Widget>[
Container(
margin: EdgeInsets.only(left: 40),
width: MediaQuery.of(context).size.width * 0.5,
child: ListView.builder(
itemCount: _places.length,
itemBuilder: (ctx, int index) {
return Container(
padding: EdgeInsets.only(top: 50),
child: Column(
children: <Widget>[
Text(_places[index]['name'], style: TextStyle(fontSize: 20),),
Container(
padding: EdgeInsets.only(top: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Card(
elevation: 40.0,
child: Container(
width: 200,
child: Image(image: AssetImage('assets/images/500place.jpg')),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 7),
child: Row(
children: <Widget>[
Icon(Icons.favorite_border, size: 20),
Spacer(),
Text(
_places[index]['where'],
),
],
)
),
],
),
);
}),
)
],);
}
}
The screen output i use Navigation rale so that's why I set the width and its working fine without Column widget
You can copy paste run full code below
Step 1: Provide height when use PlaceList() , you can use Expanded(child: PlaceList())
Step 2: add shrinkWrap: true for ListView
Step 3: Use Expaneded flex to provide height for Container() 1 and 2
Column(
children: <Widget>[
Expanded(
flex: 3,
...
Expanded(
flex: 1,
child: Center(child: Container(child: Text("Second Container"))))
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Expanded(child: PlaceList()),
],
),
),
);
}
}
class PlaceList extends StatefulWidget {
#override
_PlaceListState createState() => _PlaceListState();
}
class _PlaceListState extends State<PlaceList> {
final List _places = [
{'name': 'Hunza', 'where': 'Gilgit Baltistan'},
{'name': 'Skardu', 'where': 'Gilgit Baltistan'},
{'name': 'Murree', 'where': 'Gilgit Baltistan'},
{'name': 'abc', 'where': 'def'},
];
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
flex: 3,
child: Container(
margin: EdgeInsets.only(left: 40),
width: MediaQuery.of(context).size.width * 0.5,
child: ListView.builder(
shrinkWrap: true,
itemCount: _places.length,
itemBuilder: (ctx, int index) {
return Container(
padding: EdgeInsets.only(top: 50),
child: Column(
children: <Widget>[
Text(
_places[index]['name'],
style: TextStyle(fontSize: 20),
),
Container(
padding: EdgeInsets.only(top: 20),
child: ClipRRect(
borderRadius: BorderRadius.circular(20.0),
child: Card(
elevation: 40.0,
child: Container(
width: 200,
child: Image(
image: AssetImage(
'assets/images/500place.jpg')),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 7),
child: Row(
children: <Widget>[
Icon(Icons.favorite_border, size: 20),
Spacer(),
Text(
_places[index]['where'],
),
],
)),
],
),
);
}),
),
),
Expanded(
flex: 1,
child: Center(child: Container(child: Text("Second Container"))))
],
);
}
}
try adding height: // define height in double to your container
Add the shrinkWrap property to your ListView as seen below:
child: ListView.builder(
itemCount: _places.length,
shrinkWrap: true,
itemBuilder: (ctx, int index) {
return Container(...
Setting the shrinkWrap to true would result in the list wrapping its content and be as big as its children permits
You could also add a height to your Container
return Container(
height: 90,
...
)
Related
In my flutter application I want to create a timetable widget as below which will scroll horizontally and vertically with corresponding heading. The timetable should have 'Day' as horizontal heading and 'Period' as vertical heading. During horizontal scrolling the 'Period' header should freeze and horizontal 'Day' header should scroll with data. Similarly, during vertical scrolling the 'Day' header should freeze and vertical 'Period' header should scroll with data. How can I achieve a widget like that.Please help..
In Android we can obtain the above type of scrolling by extending HorizontalScrollView & VerticalScrollView.
You can archive this using nested listView widgets.
You can try this approach:
class TimeTableView extends StatefulWidget {
const TimeTableView({super.key});
#override
State<TimeTableView> createState() => _TimeTableViewState();
}
class _TimeTableViewState extends State<TimeTableView> {
final periodsSlots = 15;
final double containerHeight = 55.0;
final double containerWidth = 80;
final days = [
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
final subjects = [
"Maths",
"Hindi",
"English",
"Chemistry",
"History",
"Geography",
];
late ScrollController mainController;
late ScrollController secondController;
#override
void initState() {
super.initState();
secondController = ScrollController();
mainController = ScrollController()
..addListener(() {
if (mainController.hasClients && secondController.hasClients) {
secondController.jumpTo(mainController.offset);
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Time Table"),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: PageView(
children: [
Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: [
// Top header View
SizedBox(
height: containerHeight,
width: containerWidth,
child: CustomPaint(
painter: RectanglePainter(),
child: Stack(
children: const [
Align(
alignment: Alignment.topRight,
child: Padding(
padding: EdgeInsets.all(4.0),
child: Text("Day"),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: EdgeInsets.all(4.0),
child: Text("Period"),
),
),
],
),
),
),
Expanded(
child: SizedBox(
height: containerHeight,
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
controller: mainController,
child: Row(
children: List<Widget>.generate(
days.length,
(index) => Container(
height: containerHeight,
width: containerWidth,
color: bgColorHeader(index),
child: Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8),
child: Center(child: Text(days[index])),
),
),
),
),
),
),
)
],
),
SizedBox(
// Added fixed size to scroll listView horizontal
height: 500,
child: ListView.builder(
physics: const ClampingScrollPhysics(),
padding:
EdgeInsets.zero, // remove listview default padding.
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: periodsSlots,
itemBuilder: (context, index) => Container(
height: containerHeight,
width: containerWidth,
color: bgColorHeader(index),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
// period header
Padding(
padding: EdgeInsets.zero,
child: SizedBox(
width: containerWidth,
height: containerHeight,
child: Center(child: Text("period ${index + 1}")),
),
),
// period subjects
Expanded(
child: SizedBox(
height: containerHeight,
child: SingleChildScrollView(
physics: const ClampingScrollPhysics(),
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
controller: secondController,
child: Row(
children: List<Widget>.generate(
subjects.length,
(index) => Container(
color: Colors.white,
child: Container(
height: containerHeight,
width: containerWidth,
color: bgColorSubject(index),
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4),
child: Text(subjects[index]),
)),
),
),
),
),
),
),
)
],
),
),
),
)
],
),
],
),
),
);
}
// Alternate background colors
Color bgColorHeader(int index) =>
index % 2 == 0 ? Colors.cyan.withOpacity(0.5) : Colors.cyanAccent;
Color bgColorSubject(int index) =>
index % 2 == 0 ? Colors.grey.withOpacity(0.5) : Colors.grey;
}
// Draw cross line from top left container
class RectanglePainter extends CustomPainter {
#override
void paint(Canvas canvas, Size size) {
final backgroundPaint = Paint()
..color = Colors.cyanAccent
..strokeWidth = 2.0
..strokeCap = StrokeCap.round;
final crossLine = Paint()
..color = Colors.white
..strokeWidth = 2.0
..strokeCap = StrokeCap.round;
// Draw the rectangle
canvas.drawRect(Offset.zero & size, backgroundPaint);
// Draw the cross line
canvas.drawLine(Offset.zero, Offset(size.width, size.height), crossLine);
//canvas.drawLine(Offset(0, size.height), Offset(size.width, 0), crossLine);
}
#override
bool shouldRepaint(RectanglePainter oldDelegate) => false;
}
Scrolling widgets will create a default scroll controller (ScrollController class) if none is provided. A scroll controller creates a ScrollPosition to manage the state specific to an individual Scrollable widget.
To link our scroll controllers we’ll use linked_scroll_controller, a scroll controller that allows two or more scroll views to be in sync.
import 'package:flutter/material.dart';
import 'package:linked_scroll_controller/linked_scroll_controller.dart';
class ScrollDemo extends StatefulWidget {
#override
_ScrollDemoState createState() => _ScrollDemoState();
}
class _ScrollDemoState extends State<ScrollDemo> {
final List<String> colEntries = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split('');
final List<String> rowEntries =
Iterable<int>.generate(15).map((e) => e.toString()).toList();
late LinkedScrollControllerGroup _horizontalControllersGroup;
late ScrollController _horizontalController1;
late ScrollController _horizontalController2;
late LinkedScrollControllerGroup _verticalControllersGroup;
late ScrollController _verticalController1;
late ScrollController _verticalController2;
#override
void initState() {
super.initState();
_horizontalControllersGroup = LinkedScrollControllerGroup();
_horizontalController1 = _horizontalControllersGroup.addAndGet();
_horizontalController2 = _horizontalControllersGroup.addAndGet();
_verticalControllersGroup = LinkedScrollControllerGroup();
_verticalController1 = _verticalControllersGroup.addAndGet();
_verticalController2 = _verticalControllersGroup.addAndGet();
}
#override
void dispose() {
_horizontalController1.dispose();
_horizontalController2.dispose();
_verticalController1.dispose();
_verticalController2.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('sync scroll demo'),
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Container(
width: 75,
height: 75,
color: Colors.grey[200],
),
const SizedBox(width: 10),
Container(
height: 75,
width: 400,
color: Colors.blue[100],
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _horizontalController2,
child: HeaderContainer(rowEntries: rowEntries),
),
)
],
),
const SizedBox(height: 10),
Row(
children: <Widget>[
Container(
width: 75,
height: 400,
color: Colors.blue[100],
child: SingleChildScrollView(
controller: _verticalController2,
child: ColumnContainer(
colEntries: colEntries,
),
),
),
const SizedBox(width: 10),
SizedBox(
width: 400,
height: 400,
child: SingleChildScrollView(
controller: _verticalController1,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: _horizontalController1,
child: BodyContainer(
rowEntries: rowEntries,
colEntries: colEntries,
),
),
),
)
],
),
],
),
),
),
);
}
}
class ColumnContainer extends StatelessWidget {
final List<String> colEntries;
const ColumnContainer({
Key? key,
required this.colEntries,
}) : super(key: key);
#override
Widget build(BuildContext context) {
int numberOfRows = colEntries.length;
return Column(
children: List.generate(
numberOfRows,
(i) {
return Container(
height: 75,
width: 75,
decoration: BoxDecoration(border: Border.all(color: Colors.white)),
child: Center(child: Text(colEntries[i])),
);
},
),
);
}
}
class HeaderContainer extends StatelessWidget {
final List<String> rowEntries;
const HeaderContainer({
Key? key,
required this.rowEntries,
}) : super(key: key);
#override
Widget build(BuildContext context) {
int _numberOfColumns = rowEntries.length;
return Row(
children: List.generate(
_numberOfColumns,
(i) {
return Container(
height: 75,
width: 75,
decoration: BoxDecoration(border: Border.all(color: Colors.white)),
child: Center(child: Text(rowEntries[i])),
);
},
),
);
}
}
class BodyContainer extends StatelessWidget {
final List<String> colEntries;
final List<String> rowEntries;
const BodyContainer({
Key? key,
required this.colEntries,
required this.rowEntries,
}) : super(key: key);
#override
Widget build(BuildContext context) {
int _numberOfColumns = rowEntries.length;
int _numberOfLines = colEntries.length;
return Column(
children: List.generate(_numberOfLines, (y) {
return Row(
children: List.generate(_numberOfColumns, (x) {
return TableCell(item: "${colEntries[y]}${rowEntries[x]}");
}),
);
}),
);
}
}
class TableCell extends StatelessWidget {
final String item;
const TableCell({
Key? key,
required this.item,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 75,
width: 75,
decoration: BoxDecoration(border: Border.all(color: Colors.grey)),
child: Center(child: Text(item)),
);
}
}
I found these solutions from these 2 links.
Flutter: How to create linked scroll widgets
Flutter: Creating a two-direction scrolling table with a fixed head and column
I have a search page. I display 2 containers with information on the search page. But I ran into a problem, my bottom station container goes off the screen and I need to scroll the page to see the information. How can I put 2 containers on the screen and not have to scroll the page so that 2 containers fit on the same screen?
1
Widget _addresses(Size size, StationCubit stationCubit) => ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: SizedBox(
width: size.width,
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: Container(
padding: const EdgeInsets.only(left: 20, top: 17),
decoration: BoxDecoration(
color: constants.Colors.greyXDark.withOpacity(0.8),
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
controller: _addressesController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Addresses',
style: constants.Styles.smallBookTextStyleWhite,
),
const SizedBox(height: 25),
2
Widget _station(Size size, StationCubit stationCubit) => ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: SizedBox(
width: size.width,
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: Container(
padding: const EdgeInsets.only(left: 20, top: 17),
decoration: BoxDecoration(
color: constants.Colors.greyXDark.withOpacity(0.8),
borderRadius: BorderRadius.circular(24),
),
child: SingleChildScrollView(
controller: _stationController,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text(
'Station',
style: constants.Styles.smallBookTextStyleWhite,
),
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Column(
children: [
Expanded(
child: Container(
color: Colors.deepPurple,
child: ListView.builder(itemBuilder: (c, i) {
return Text("Test $i");
})),
),
Expanded(
child: Container(
color: Colors.deepOrange,
child: ListView.builder(itemBuilder: (c, i) {
return Text("Test $i");
})),
),
],
));
}
}
Try placing both containers in column and wrap both container with flexible/expanded to expand containers in full screen.
Example code:
column(
children: [
Expanded(
child: Container(child: Text("Container 1")
),
Expanded(
child: Container(child: Text("Container 2")
)
]
)
Use 2 Expanded container in single column
column( children: [ Expanded( child: Container(child: Text("Container 1") ), Expanded( child: Container(child: Text("Container 2") ) ] ).
Abdul Rahman Panhyar your answer is right but Max need to show data came from any API so there is a chance of bulk data and just wrapping the container with expanded will disrupt the UI. so what is suggest you can divide your screen in two parts then in each part you can use Listview builder so it will be inner scrollable.
I am trying to achieve something like this in flutter. I have a horizontal scrollable which has these rounded containers. I want the width of these containers to shrink if the elements in the scrollable is more than 3 and it should expand as per the image if the elements are less than 2. What i want is exactly like this image, i have been reading about flexible widget but when i wrap it inside a scrollable row it gives layout specific issues. Any workaround to achieve this?
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
SingleChildScrollView(
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
child: Row(
children: [
...List.generate(
9,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.green,
),
height: 100,
width: 100,
),
),
)
],
)),
SizedBox(
height: 20,
),
Row(
children: [
...List.generate(
2,
(index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 100,
width: 180,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(20))),
))
],
),
SizedBox(
height: 20,
),
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 100,
width: 350,
decoration: BoxDecoration(
color: Colors.green,
borderRadius: BorderRadius.circular(20))),
),
],
)
],
),
),
);
}
The above build method produces the following result.(The values here are hardcoded and is just for demonstration). The list values are going to be dynamic and the desired result should be like the one in the video. How do i proceed with this?
https://streamable.com/w142je
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(debugShowCheckedModeBanner: false, home: MyHomePage());
}
}
class MyHomePage extends StatefulWidget {
final String hintText = 'hing';
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
#override
Widget build(BuildContext context) {
var list1 = List.filled(2, '2');
var list2 = List.filled(4, '4');
var list3 = List.filled(1, '1');
return SafeArea(
child: Scaffold(
body: Column(
children: [
_getList(context, list1),
_getList(context, list2),
_getList(context, list3),
],
),
),
);
}
Widget _getList(BuildContext context, List<String> list) {
bool ownSize = list.length == 2;
if (ownSize) {
return SingleChildScrollView(
padding: EdgeInsets.zero,
scrollDirection: Axis.horizontal,
child: Row(
children: list.map((t) => rowItem(t, 250)).toList(),
),
);
} else {
return Row(
children: list
.map(
(t) => Expanded(child: rowItem(t)),
)
.toList(),
);
}
}
Widget rowItem(String text, [double? width]) {
return Container(
margin: const EdgeInsets.all(8.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.green,
),
height: 100,
width: width,
alignment: Alignment.center,
child: Text(text),
);
}
}
I'm trying to use Flow widget instead of BottomNavigationBar.
this is my code.
#override
Widget build(BuildContext context) {
final delegate = S.of(context);
return SafeArea(
child: Scaffold(
drawer: DrawerWidget(),
body: Stack(
children: [
_pages[_selectedPageIndex]['page'],
Positioned(
child: Container(
child: Flow(
delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
children: menuItems
.map<Widget>((IconData icon) => flowMenuItem(icon))
.toList(),
),
),
),
]),
}
But after adding left, right, bottom, or top properties to the Positioned widget, the Flow widget gon.
You can copy paste run full code below
You can use ConstrainedBox and set Stack fit and Positioned with Container
SafeArea(
child: Scaffold(
body: ConstrainedBox(
constraints: BoxConstraints.expand(),
child: Stack(
alignment: Alignment.topLeft,
fit: StackFit.expand,
children: [
...
Positioned(
left: 0,
top: 0,
child: Container(
alignment: Alignment.topLeft,
width: MediaQuery.of(context).size.width,
height: 65,
child: FlowMenu()))
]),
),
),
);
working demo
full code
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: FlowTest(),
);
}
}
class FlowTest extends StatefulWidget {
#override
_FlowTestState createState() => _FlowTestState();
}
class _FlowTestState extends State<FlowTest> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: ConstrainedBox(
constraints: BoxConstraints.expand(),
child: Stack(
alignment: Alignment.topLeft,
fit: StackFit.expand,
children: [
ListView(
shrinkWrap: true,
children: <Widget>[
Column(
children: <Widget>[
SizedBox(height: 20.0),
ListView.builder(
shrinkWrap: true,
itemCount: 5,
physics: PageScrollPhysics(),
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Container(
height: 50.0,
color: Colors.green,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.format_list_numbered,
color: Colors.white),
Padding(
padding: const EdgeInsets.only(right: 5.0)),
Text(index.toString(),
style: TextStyle(
fontSize: 20.0, color: Colors.white)),
],
),
),
Container(
child: GridView.count(
crossAxisCount: 3,
shrinkWrap: true,
physics: PageScrollPhysics(),
childAspectRatio: 1.2,
children: List.generate(
8,
(index) {
return Container(
child: Card(
color: Colors.blue,
),
);
},
),
),
),
SizedBox(height: 20.0),
],
);
},
),
],
),
],
),
Positioned(
left: 0,
top: 0,
child: Container(
alignment: Alignment.topLeft,
width: MediaQuery.of(context).size.width,
height: 65,
child: FlowMenu()))
]),
),
),
);
}
}
class FlowMenu extends StatefulWidget {
#override
_FlowMenuState createState() => _FlowMenuState();
}
class _FlowMenuState extends State<FlowMenu>
with SingleTickerProviderStateMixin {
AnimationController menuAnimation;
IconData lastTapped = Icons.notifications;
final List<IconData> menuItems = <IconData>[
Icons.home,
Icons.new_releases,
Icons.notifications,
Icons.settings,
Icons.menu,
];
void _updateMenu(IconData icon) {
if (icon != Icons.menu) setState(() => lastTapped = icon);
}
#override
void initState() {
super.initState();
menuAnimation = AnimationController(
duration: const Duration(milliseconds: 250),
vsync: this,
);
}
Widget flowMenuItem(IconData icon) {
final double buttonDiameter =
MediaQuery.of(context).size.width / menuItems.length;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: RawMaterialButton(
fillColor: lastTapped == icon ? Colors.amber[700] : Colors.blue,
splashColor: Colors.amber[100],
shape: CircleBorder(),
constraints: BoxConstraints.tight(Size(buttonDiameter, buttonDiameter)),
onPressed: () {
_updateMenu(icon);
menuAnimation.status == AnimationStatus.completed
? menuAnimation.reverse()
: menuAnimation.forward();
},
child: Icon(
icon,
color: Colors.white,
size: 45.0,
),
),
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Flow(
delegate: FlowMenuDelegate(menuAnimation: menuAnimation),
children: menuItems
.map<Widget>((IconData icon) => flowMenuItem(icon))
.toList(),
),
);
}
}
class FlowMenuDelegate extends FlowDelegate {
FlowMenuDelegate({this.menuAnimation}) : super(repaint: menuAnimation);
final Animation<double> menuAnimation;
#override
bool shouldRepaint(FlowMenuDelegate oldDelegate) {
return menuAnimation != oldDelegate.menuAnimation;
}
#override
void paintChildren(FlowPaintingContext context) {
double dx = 0.0;
for (int i = 0; i < context.childCount; ++i) {
dx = context.getChildSize(i).width * i;
context.paintChild(
i,
transform: Matrix4.translationValues(
dx * menuAnimation.value,
0,
0,
),
);
}
}
}
I'm new to Flutter.
What I'm trying to achieve is a page that has a transparent AppBar with a widget behind it. That's how it looks now:
The problem is that, I can't make the page scroll when the content is bigger then the viewport height, even adding a SingleChildScrollView or adding the content inside a ListView, it just don't scrolls.
This is the page:
import 'package:cinemax_app/src/blocs/movie_bloc.dart';
import 'package:cinemax_app/src/components/movie/movie_header.dart';
import 'package:cinemax_app/src/models/movie.dart';
import 'package:flutter/material.dart';
import 'package:share/share.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
class MoviePage extends StatefulWidget {
final int movieId;
MoviePage({ this.movieId });
#override
_MoviePageState createState() => _MoviePageState();
}
class _MoviePageState extends State<MoviePage> {
#override
void initState() {
super.initState();
movieBloc.fetchMovie(widget.movieId);
}
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: movieBloc.movie,
builder: (context, snapshot) {
final _movie = snapshot.data as MovieModel;
return Scaffold(
body: SafeArea(
child: snapshot.hasData ?
Stack(
children: <Widget>[
ListView(
shrinkWrap: true,
children: <Widget>[
MovieHeader(movie: _movie),
Container(
padding: EdgeInsets.only(top: 45, bottom: 15, left: 15, right: 15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Sinopse:', style: Theme.of(context).textTheme.title),
HtmlWidget(
_movie.sinopsis,
bodyPadding: EdgeInsets.only(top: 15),
textStyle: TextStyle(color: Colors.grey),
)
],
),
)
]
),
AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
actions: <Widget>[
PopupMenuButton(
icon: Icon(Icons.more_vert),
itemBuilder: (BuildContext context) {
return <PopupMenuItem>[
PopupMenuItem(
child: Text('Partilhar'),
value: 'share'
),
PopupMenuItem(
child: Text('Comprar bilhete'),
value: 'share',
enabled: false,
),
];
},
onSelected: (selectedPopupValue) {
switch (selectedPopupValue) {
case 'share': {
final movieSlug = _movie.slug;
final movieAddress = 'https://cinemax.co.ao/movie/$movieSlug';
Share.share(movieAddress);
}
}
},
)
],
),
]
) :
Center(
child: CircularProgressIndicator(),
)
),
);
}
);
}
}
The MovieHeader widget:
import 'dart:ui' as prefix0;
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cinemax_app/src/models/movie.dart';
import 'package:flutter/material.dart';
import 'movie_cover.dart';
class MovieHeader extends StatelessWidget {
const MovieHeader({Key key, #required MovieModel movie}) : _movie = movie, super(key: key);
final MovieModel _movie;
#override
Widget build(BuildContext context) {
return Container(
height: 250,
color: Colors.black,
child: Column(
children: <Widget>[
Expanded(
child: Stack(
fit: StackFit.expand,
overflow: Overflow.visible,
children: <Widget>[
new MovieBanner(movie: _movie),
Positioned(
bottom: -15.0,
left: 15.0,
right: 15.0,
child: Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Container(
width: 125.0,
child: MovieCover(imageUrl: _movie.coverUrl)
),
Padding(padding: EdgeInsets.only(right: 15.0),),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Text(
_movie.name,
style: TextStyle(
fontSize: 16.0,
fontWeight: FontWeight.bold,
)
),
),
],
),
Padding(padding: EdgeInsets.only(bottom: 10.0),),
Text(
_movie.genresList,
style: TextStyle(
fontSize: 10.0,
color: Colors.white.withOpacity(0.6)
),
),
Padding(padding: EdgeInsets.only(bottom: 35.0),)
],
),
)
],
)
),
)
],
)
),
],
),
);
}
}
class MovieBanner extends StatelessWidget {
const MovieBanner({
Key key,
#required MovieModel movie,
}) : _movie = movie, super(key: key);
final MovieModel _movie;
#override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
Opacity(
child: CachedNetworkImage(
imageUrl: _movie.bannerUrl,
fit: BoxFit.cover,
),
opacity: 0.5,
),
Positioned(
child: ClipRect(
child: BackdropFilter(
child: Container(color: Colors.black.withOpacity(0)),
filter: prefix0.ImageFilter.blur(sigmaX: 5, sigmaY: 5),
),
),
)
],
);
}
}
Why is it happening? What I'm doing wrong?
An Example of Scrolling ListView using ListView Builder
class ScrollingList extends StatelessWidget{
List<String> snapshot= ["A","B","C","D","E","F","G"]
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder( //<----------- Using ListViewBuilder
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Card( //<--------- Using Card as per my requirement as a wrapper on List tile, you can use any other UI Element
child: ListTile( // populating list tile with tap functionality
title: Text(
'${snapshot.data[index]}',
maxLines: 1,
),
onTap: () {
print('TAPPED = ${snapshot.data[index]}') //<---- do anything on item clicked eg: open a new page or option etc.
}),
);
},
);
)
}
for any reference of single child scroll view here is a link