Achieving this layout in flutter - flutter

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),
);
}
}

Related

Flutter : Horizontally and Vertically Scrolling Time Table with two sided header

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

How to put two containers on the same screen without page scrolling?

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.

Flutter web - Fade in when scroll down

I want to build a portfolio website with flutter and I can't find fade-in animation while scrolling down,
there are animatedBox and a lot of animation but none of them have listeners for fading in while scrolling down.
Can anyone help me with this? An example would be more helpful.
Thank you
After a while, I find a way to do that, we should use the scrollController and mediaQuery for riching this goal,
source code
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Ali Azimoshan',
debugShowCheckedModeBanner: false,
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController _scrollController;
var selectedSlide;
imageBox() {
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/image-1.jpg',
),
),
),
),
Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/image-2.jpg',
),
),
),
),
Container(
width: MediaQuery.of(context).size.width / 3,
height: MediaQuery.of(context).size.height / 3,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
'assets/images/image-3.jpg',
),
),
),
),
],
),
);
}
List allSlides = [
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false},
{'widget': Widget, 'selected': false}
];
#override
void initState() {
super.initState();
_scrollController = ScrollController();
_scrollController.addListener(changeSelector);
setState(() {
selectedSlide = allSlides[0];
selectedSlide['selected'] = true;
});
}
changeSelector() {
var maxScrollVal = _scrollController.position.maxScrollExtent;
var divisor = (maxScrollVal / allSlides.length) + 20;
var scrollValue = _scrollController.offset.round();
var slideValue = (scrollValue / divisor).round();
// var currentSlide = allSlides.indexWhere((slide) => slide['selected']);
setState(() {
// allSlides[currentSlide]['selected'] = false;
selectedSlide = allSlides[slideValue];
selectedSlide['selected'] = true;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
child: ListView(
controller: _scrollController,
children: allSlides.map((element) {
return getCards(element);
}).toList(),
),
)
],
),
);
}
Widget getCards(slide) {
return Padding(
padding: EdgeInsets.all(0),
child: AnimatedCrossFade(
firstChild: imageBox(),
duration: Duration(seconds: 1),
secondChild: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
color: Colors.transparent,
),
crossFadeState: slide['selected']
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
),
);
}
}
Ok here's a little demo
here's the code
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';
class overall extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<overall> {
double offset = 0;
#override
Widget build(BuildContext context) {
final height = MediaQuery.of(context).size.height;
final width = MediaQuery.of(context).size.width;
final nameStyle = Theme.of(context).textTheme.headline2;
final descriptionStyle = Theme.of(context).textTheme.headline4;
final workStyle = Theme.of(context).textTheme.headline6;
return Material(
child: NotificationListener<ScrollNotification>(
onNotification: updateOffsetAccordingToScroll,
child: ScrollConfiguration(
behavior: NoScrollGlow(),
child: Stack(
children: <Widget>[
Positioned(
top: -.45 * offset,
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: backgroundImage,
height: height,
width: width,
fit: BoxFit.fitWidth,
),
),
Positioned(
top: -.25 * offset,
child: SizedBox(
height: height,
width: width,
child: Align(
alignment: Alignment(0, 0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
circleIcon(profileicon, 100),
Text(
'My Name',
style: nameStyle.copyWith(
color: Colors.white,
),
),
SizedBox(height: 20),
Text(
'Representing my core values here',
style: descriptionStyle.copyWith(
color: Colors.white,
),
),
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Text(
"Currently Working with",
style: workStyle.copyWith(
color: Colors.white,
),
),
),
Padding(
padding: const EdgeInsets.only(top: 18.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(right: 10.0),
child: circleIcon(fluttericon, 40),
),
Padding(
padding: const EdgeInsets.only(left: 20.0),
child: circleIcon(darticon, 40)),
],
),
)
],
)),
),
),
SingleChildScrollView(
child: Column(
children: <Widget>[
SizedBox(height: height),
Container(
height: height,
width: width,
color: Colors.blueAccent,
)
],
),
)
],
),
),
),
);
}
bool updateOffsetAccordingToScroll(ScrollNotification scrollNotification) {
setState(() => offset = scrollNotification.metrics.pixels);
return true;
}
}
class NoScrollGlow extends ScrollBehavior {
#override
Widget buildViewportChrome(
BuildContext context,
Widget child,
AxisDirection axisDirection,
) {
return child;
}
}
circleIcon(String icon, size) {
return CircleAvatar(
radius: size,
backgroundImage: NetworkImage(icon),
);
}
const backgroundImage = 'https://wallpaperaccess.com/full/7033.jpg';
const profileicon =
'https://flutter.github.io/assets-for-api-docs/assets/widgets/owl.jpg';
const darticon =
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASYAAACsCAMAAADhRvHiAAAAxlBMVEX////w8PDv7+8qtvYBV5tAxP8CWJsDWJz4+Pj8/Pz19fX6+vrz8/MptfYAVJkAUZY1gbg6vflAo9o6w/9wzvv28u8qY5Mtu/oASpUARIUfmdrW3OLC4/Tj6e/P5/PN7v8AT5ep3feU3P+BpMfM2OIcktO05v8gmtne9f+h2vfs+f+L2f9Lyf9dq9oeerU4jMO9ytkXX549cacAa6yUyuoAQZCJsNFPf7B4nMBkjLaatdGmvNMra6eDoLuyx9w4mNBEruMPWo4wj9P9AAAKPklEQVR4nO2dfWPTNhDG7TSlfpsDDabZStrShgKjA8o2WmAb2/f/UrMlv0iWZEnWSbEd6y8eKKnv59PpHseWPQ+NYOHnY4FFzBEhEiFHxPjnOCLgCB+NiCMSUkRIJKTwOYI6bJsxeDOmGdOMacY0ZExoVJ9KiBCLUCI8LGJSBBzhIxFxRIJEwhEREj5HUIdtMwYvmIfC4J1443PNO73O8tVODP4EKof16ufPmGZMMybXmOYSrh6DF/jk6eWI8rgxaPJc++TppUXAEeLTS4msGPS55p146rBtxlBhcjolFuIpgWG8ffnq3btXFxmHTLRgpsRhmpXb5+tyHF//ymKisulAMWXR7XGOpxrr9ftwxtTGlPmvjhtGJajLUWDifSpH9KtNC0IkOaS7FqRinF1n6McMapN5DF6MRhChIRMxRwQwIoyYTKoS6n2mdHA2YxhG3+RnC24mlZyuiYM7YOuLIAkpFfOumQUHa1bCrkwi8unAMd3KIJWcDhqTCiTM6YCt721nTaI5Zfss4WExctuY5MPHIi6Fx4iQI2JGhKUIkPAokSAR5SIvSt2FmzPv8v8VoY9LPPKwPdsxlH3VXtpL9UxqOO2tvZT9CltmRRdSxWmgZsUGptzg6kMqOR0MJuTdekDCnAaKCbo2CQyuMqd4P7UJFfKwNIeUiJGItUSAP6FDiAyuKqfSB4sP20oMTvsms0yq8ok40glaX3zRzZQS7YOnZ1ZigEwiOE0V061ZTWpzmiYmRYOrMu7uGh88Mev724enUOPjxx+nzyof7Nj6hgHykwkWsUzg9TOUiXIxTaJPb07TJ2Dj/v6vp6fXHnPYNmPwmPkB315Gn0/Xv6yW9OiHCP/fNF3+/gdz2CO3vsnuz9NnRzSn/rlUfkC6+aKOaRSeLnrY5JjOSE79KdWclpubaWHabVY5JoKTCSSa03Awmc/rhxXCVHMypNSA2tzgm3AcWl9rq4S33SwxpqOzNysQSg2nx8DVSme754i+XlWYUD5BUCLyiTjsMVvf5HyzrDEVnGAw0ZzGb1aCxysCkyVO48e0zSkRmDo5nbSGMqfRY4oeW5hEnNqIFEg1nMZuff0t6gFITFxOAkgSUjWnwHdlfe1cR/a+XDGYWE5dkLpA1X3mo2cxBgfWN8Zx0JhanGSQOkCRvmXM1vfbFQ8TyUkFkiKnsXq6OLxPuZgaToqURKCWJKexYvK+b7iTDnFK9SgpcOIdtjNM/ee1H5TJxMGE8kkHkgon335tQr+iXBHxkzDlwy+UCDkiZgU+4KhKJh6mIp+WAJyWDafcB4PHUD/aY7Fv+ivtwGSB042FGOxb33+qZOJj4nLKy1VXbe/EVHICjcGBWfmcdmNiOLUJ9OM0Mkyf6mQSYaI58WaUCqdli9PIMDXJJMSErtOJIXFBSTnZwWSrhO+aZBJjQtd9OyBxOHVjqn0wdAnv8yiRwqNN4UPzfdMTMSacTx2UWFBSTh5UDITwyNyCa80SojJ1YiryqZtSm5MEU7nejcP6RmQydWJSue4r4bTkcBqFp/PJyiTBpJ1PsnRCnEaBqfjWSRmTdj7JMIl88OAwkckkx6SQT3qYBD54cJjoZJJiqq6r9OXEYFpu/o5gMVnom/xzOpnkmOScNNMpfWEYgwPri7910sKkx0kDU98YHJiVLUlJEVNen7pvL9CbdSPAFN20kkkJU55P6pymgIlJJjVMMk77xUSVcIhdKelk0sCkwYn5N/gSXmPCJRx6h8g4Spc9MUnquB6mEDQqj4aGhtmWZt82vTF1c9KZdemLxDeIoRHW2suT/tlUrHep0hU6OSbg9hIa03c6mTQxFZwOAtN9aoSpY95NCBPxrVNPTGIfPAhMMCW8+QqzNyYhJ80SbrIMNcKO9d21k6kHJpX7DuWY+sfgwPrSrWVPTII63gtTjxgcmBVmzvXCxOc0HUxbJpn6YSrWu67vyhmE48LElqaemHj5NCBMxV/yd6VEIuEItFPQAhoT64N15hxRwrVjoEWFCTm76stNVgRa4hwOE9NnamIK+8YQ5wAY4VXQIPomf8tU8P6Y2tczNTEN2fpGn7mc+mGi8+lEE9OQzUrE9k0GmChOXZTGhinhF6e+mAhOesk0cEwL76G934ARpvr6Uycll5ggSnguuC1Bf0yVv9PHBGx9cS/Fay/FL2TgtGaVCL5yXJ0BJszpRB+TQQyYQpk/pfDJ3MJC3IUnHNHqYBft63KGmApO2pS6unB5DAsSk6Xv6ZLzlOFkhInhZIhpAJ6uENHuqn2d1wzT0dnrVRelcWLKObXyyRQTlU9KlFxgMrC+WGTtfDLFRHLSxNQ3hjYmrdt/I47g3E0ct+qTMabi+rgOpQKTYQy08CpoMH1T2XNk9Lwzx1TUJ8F99gJMQ7a+zQ3Pu2UKikl4nz2X0tDNSi0oThCYUD5NDhPFCQRTwUmV0ngwkZxgMHE5ucYEWsLRn5PdifiRaCBOAkrw1pfc9KoUESXw+xQiicDvYAgpEVb5BIWJ5STG5MHEUG4xJrO+C7ltJLsxujWr+gIwTG1OIkp0F24UgzWzQvyKsj7BYaI5CSmNwdORvyLarVJQTBSnyWDCPnj14/gnC5zElJxaX1JIbKN4Xhc+ePUREFPNqYOSoDb1jaGxvpytnUpzqCU4W00Fu9Xqwx0gppJTF6VqpYOKwZL1pXqOPJ+e3AFSwpw6KcH3TWRu2dnUJ1/vrv49g+YkwzQWs0JsoR/tPkAWJwVOo8SUczoFpSTlNE5M+Xp3BJtOEk4jsr7U7cHZxZlLTlatL735c0T4YFXR8Q6GC5f5VDcEQDFYby/rTc8zl5zA20sWE/CmPvV96C45jc3TEZj8ghPsOHv9s2D8N15MOac19Hi5zcc5HtttI7bWMYkvy1HzWvWSFvlChuwC6k1Q5VhfoiMtqmx181FCCqAYfN5KF3GEbJVIOIKzZGRv4V4sVmJqL9BWYvAqaJb7ptoHXwC8yY/A9NJftB9WshFDjYmYH1bfxJpzgsVET+sRbl3Mf3scKKfpYgLlNGFMPmB9co7JUQkvfTDUeueshFeXv4t7nkKZiDgi0BLo3qrcBwPl0/oyVDhs8xhs3FQobi/rWQA173B7yUxr6BjcmhWiWABxEmEaz9bFkncRwtSnyWOC4bRHTHB3pHRiAuEkrU0wMfjQj/ZQZ0Io8DsYAHxweYXAUQyO+6bq9Jrn02StL3lGzefdlM0KUWBN+4IDwWTqgw8Fk2E+Tdr6UjtEGdUn19ZX9gRUIBGqjxJxRGww79aXKg9umccAu5UMbxsW6ZQIDb6XOuO0lxZi2KNZoXzw877jLYvJQgzDwJQX8izDwsvQoEQoFLxqO2VMNtdS95gU9iEYPKY+MVh5JFoTk/k7dTquEMDEsF/rC7YrpfUYakwDmRIDrX4zphnTjGlfmByVcIiXSiyYFzJYjwH8lQ/THJM41w5i8CdQOYZmVmZMM6YZkzkmTi0cneNyFYND/05admeXkY1jkGIawZRwMK3/BwTvxixwGjpsAAAAAElFTkSuQmCC';
const fluttericon =
'https://cdn.iconscout.com/icon/free/png-512/flutter-2038877-1720090.png';

Add New Widget on button click with a finction that returns a widget

Hello i am new to Flutter and I want to know if there is a way to add new Widgets with a button click.
I looked into many stack overflow similar Questions. but due to my poor knowledge most of them seems complex to me and hard to grasp. All i need to do is add some containers below old build containers
class MedPreC extends StatefulWidget {
#override
_MedPreCState createState() => _MedPreCState();
}
Widget returnWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
height: 40,
color: Colors.red,
),
);
}
class _MedPreCState extends State<MedPreC> {
var child2 = Column(
children: [
returnWidget(),
],
);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(
child: Container(
color: Colors.yellow,
height: 400,
width: double.infinity,
child: child2,
),
),
RaisedButton(
child: Text("Add"),
onPressed: () {
setState(() {
//
child2.children.add(returnWidget());
//
});
},
)
],
),
);
}
}
This is the code i have made so far. This whole code will be called inside another class with scafold and stuffs
returnWidget() Returns a red container
child2 is a Column called inside a yellow Container with one red container as one of its children
i need to add more redcontainers on button press
Thank you thats all
Try this
class AddWidget extends StatefulWidget {
#override
_AddWidgetState createState() => _AddWidgetState();
}
class _AddWidgetState extends State<AddWidget> {
List<Widget> containerList = [];
Widget returnWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
height: 40,
color: Colors.red,
),
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Expanded(
child: Container(
color: Colors.yellow,
height: 400,
width: double.infinity,
child: Column(children: containerList),
),
),
RaisedButton(
child: Text("Add"),
onPressed: () {
setState(() {
containerList.add(returnWidget());
});
},
)
],
),
);
}
}
For this you need also check the overflow of widget. So you can check the below code.
import 'package:flutter/material.dart';
class MedPreC extends StatefulWidget {
#override
_MedPreCState createState() => _MedPreCState ();
}
class _MedPreCState extends State<MedPreC > {
List<Widget> data = [];
Widget CustomWidget() {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: double.infinity,
height: 40,
color: Colors.red,
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
color: Colors.yellow,
height: MediaQuery.of(context).size.height - 60,
width: double.infinity,
child: SingleChildScrollView(child: Column(children: data)),
),
],
),
bottomNavigationBar: Container(
height: 60,
width: MediaQuery.of(context).size.width,
color: Colors.white,
child: InkWell(
child: Center(
child: Container(
color: Colors.red,
width: 100,
height: 40,
child: Center(child: Text("Add"))),
),
onTap: () {
setState(() {
data.add(CustomWidget());
});
},
),
),
);
}
}

Using Flow widget instead of BottomNavigationBar in Flutter

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,
),
);
}
}
}