How to make my page scrollable when i show overlay element, that have too many items in flutter? - flutter

I have created a custom dropdown widget, to select one option form a list that i load it from local json file.
When this dropdown field is at the bottom of the screen, the options can not be displayed, because of using overlay element.
Can you help me, how can I solve htis issue?
here is the image that shows my problem
Here is my custom dropdown
import 'package:flutter/material.dart';
class CustomDropdown extends StatefulWidget {
final TextEditingController controller;
final List<Map> items;
final String label;
final String value;
const CustomDropdown({Key key, #required this.controller, #required this.items, this.label, this.value}) : super(key: key);
#override
_CustomDropdownState createState() => _CustomDropdownState();
}
class _CustomDropdownState extends State<CustomDropdown> {
final FocusNode _focusNode = FocusNode();
OverlayEntry _overlayEntry;
final LayerLink _layerLink = LayerLink();
bool isOpened = false;
#override
void initState() {
super.initState();
widget.controller.text = widget.value;
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
this._overlayEntry = this._createOverlayEntry();
Overlay.of(context).insert(this._overlayEntry);
} else {
this._overlayEntry.remove();
}
});
}
OverlayEntry _createOverlayEntry() {
RenderBox renderBox = context.findRenderObject();
var size = renderBox.size;
var offset = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(
// opaque: true,
builder: (context) => Positioned(
// left: offset.dx,
// top: offset.dy + size.height + 5.0,
width: size.width,
child: CompositedTransformFollower(
link: this._layerLink,
showWhenUnlinked: false,
offset: Offset(0.0, size.height + 5.0),
child: Material(
elevation: 12.0,
child: ListView.builder(
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
shrinkWrap: true, // new line
// physics: NeverScrollableScrollPhysics(), // new line
itemCount: widget.items.length,
itemBuilder: (_, index) {
return ListTile(
title: Column(
children: [
SizedBox(
height: 20,
),
Text(widget.items[index]["text"]),
SizedBox(
height: 20,
),
Divider()
],
),
onTap: () {
print("${widget.items[index]["text"]} Tapped");
setState(() {
_focusNode.unfocus();
widget.controller.text = widget.items[index]["text"];
});
},
);
},
),
),
),
),
);
}
#override
Widget build(BuildContext context) {
return CompositedTransformTarget(
link: this._layerLink,
child: TextFormField(
controller: widget.controller,
readOnly: true,
// initialValue: 'Test',
focusNode: this._focusNode,
decoration: InputDecoration(
labelText: widget.label.toUpperCase(),
isDense: true,
),
),
);
}
}
and here where i use it:
Form(
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Wollen Sie Ihr Profile mit einem Passwort schützen?'.toUpperCase(),
style: TextStyle(fontSize: 20.0, color: theme.inputTextColor),
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: _buildFaceIdOptions(),
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
'FaceID verwenden',
style: TextStyle(fontSize: 18.0),
),
_buildToggleButton()
],
),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: _buildPassword(),
),
SizedBox(
height: 20,
),
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: _buildRepeatPassword(),
),
SizedBox(
height: 20,
),
Padding(padding: const EdgeInsets.only(top: 15.0), child: CustomDropdown(controller: questionController, items: _questionList, label: 'Sicherheitsfrage', value: '',)),
SizedBox(
height: 20,
),
// Padding(
// padding: const EdgeInsets.only(top: 15.0),
// child: _buildPassword(),
// ),
SizedBox(
height: 120,
)
],
),
)

You can make the list inside the Overlay scrollable.
You have to set all possible values in the Positioned widget inside OverlayEntry otherwise its content won't be scrollable: if you set width then you have to also set top, bottom and left (or right but not both, read the Positioned widget specifications for that).
Once you set those values the Positioned widget contents will be scrollable.

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

Horizontal viewport was given unbounded height - Flutter

I'm a newbie in App development and encountering an error while rendering the Horizontal Card scroll.
howItWorks.dart
class HowItWorksCards extends StatefulWidget {
HowItWorksCards();
#override
_HowItWorksCardsState createState() => _HowItWorksCardsState();
}
class _HowItWorksCardsState extends State<HowItWorksCards> {
int _currentPage = 0;
PageController _pageController = PageController(viewportFraction: 0.8, keepPage: true);
List<Widget> _pages = [
SliderPage(
index: 1,
title: "Title1",
info:"Summary",
image: "assets/images/howItWorks/1.png"),
SliderPage(
index: 1,
title: "Title1",
info:"Summary",
image: "assets/images/howItWorks/1.png"),
SliderPage(
index: 1,
title: "Title1",
info:"Summary",
image: "assets/images/howItWorks/1.png"),
];
_onchanged(int index) {
setState(() {
_currentPage = index;
});
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
flex: 5,
child: PageView.builder( // this throws the exception.
controller: _pageController,
// physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: _pages.length,
onPageChanged: _onchanged,
itemBuilder: (context, int index) {
return _pages[index];
},
),
),
Flexible( // this works absolutely fine when the above Flexible widget is commented.
flex: 4,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: List<Widget>.generate(
_pages.length,
(int index) {
return AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 5,
width: (index == _currentPage) ? 30 : 10,
margin: EdgeInsets.symmetric(horizontal: 5, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: (index == _currentPage)
? AppTheme.globalTheme.primaryColor
: AppTheme.globalTheme.primaryColor
.withOpacity(0.5)));
},
)),
),
],
);
}
}
slider.dart
class SliderPage extends StatelessWidget {
final String image;
final int index;
final String title;
final String info;
SliderPage(
{#required this.image,
#required this.info,
#required this.title,
#required this.index});
#override
Widget build(BuildContext context) {
return Card(
elevation: 20,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(5.0),
height: 175,
child: Image.asset(
image,
fit: BoxFit.fitHeight,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(this.title,
style: getFontStyle(
bold: true,
color: Color(0xFF3C3C43),
fontSize: 18,
fontStyle: FontStyles.SFProDisplay),
textAlign: TextAlign.center),
),
],
),
),
Container(
padding:
const EdgeInsets.symmetric(horizontal: 10.0, vertical: 5),
child: Text(
this.info,
style: getFontStyle(
color: Color(0xFF3C3C43),
fontSize: 16,
fontStyle: FontStyles.SFProDisplay),
textAlign: TextAlign.center,
),
),
]),
);
}
}
main.dart
void main() => runApp(MaterialApp(home: AmazonOrdersInvoiceOnboarding()));
class AmazonOrdersInvoiceOnboarding extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: GoBackAppBar(
customBackGroundColor: Color(0x1affb500),
title: "",
),
body: ListView(
shrinkWrap: true,
children: [
HowItWorksCards(),
],
),
);
}
}
I'm getting some exceptions.
Horizontal viewport was given unbounded height. - Have already used Flexible. Not sure why I'm still getting this exception.
RenderBox was not laid out: RenderViewport#c29be NEEDS-LAYOUT NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I found a lot of related questions on SO, but to no avail.
This error happen when we use infinite sized widget inside one-another,
here you are using Column inside ListView, both take infinite height, if you wrap Column fixed sized widget it will solve the problem,
And I strongly suggest you to watch this video by flutter
https://www.youtube.com/watch?v=jckqXR5CrPI
on howItWorks.dart
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Flexible(
flex: 5,
child: Container(
height: 250,
child: PageView.builder(
// this throws the exception.
controller: _pageController,
// physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: _pages.length,
onPageChanged: _onchanged,
itemBuilder: (context, int index) {
return _pages[index];
},
),
),
),
Flexible(
// this works absolutely fine when the above Flexible widget is commented.
flex: 4,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: List<Widget>.generate(
_pages.length,
(int index) {
return AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 5,
width: (index == _currentPage) ? 30 : 10,
margin: EdgeInsets.symmetric(horizontal: 5, vertical: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.amber)
// (index == _currentPage)
// ? AppTheme.globalTheme.primaryColor
// : AppTheme.globalTheme.primaryColor
// .withOpacity(0.5))
);
},
)),
),
],
);
}

Flutter: Scroll view not responding

I am pretty new to flutter. I have build a landing page using grid view and added a bottom navigation bar. The navigation bar is called first after login in and I have added the screen to the navigation class. The issue am facing is that the navigation bar is on top of my grid items, when I try to scroll up, the grid items are sticky and not moving, what am I not doing right??
my home screen code
class GridDashboard extends StatelessWidget {
var services = [
"Home",
"Update",
"Bluetooth",
"Forms",
"Supervisor",
"Messages",
"Settings",
"App updates",
"Logout",
];
var images = [
"assets/home.png",
"assets/updated.png",
"assets/bluetooth.png",
"assets/todo.png",
"assets/supervisor.png",
"assets/message.png",
"assets/setting.png",
"assets/update.ico",
"assets/logout.png",
];
#override
Widget build(BuildContext context) {
List<Items> myList = [home, update, bluetooth, forms, supervisor, messages, settings, check, logout];
var color = 0xff453658;
return Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
// margin: EdgeInsets.only(top: 10),
// padding: EdgeInsets.all(20),
child: GridView.builder(
// add this
shrinkWrap: true,
itemCount: services.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
),
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
Navigator.push(context, new MaterialPageRoute<Widget>(
builder: (BuildContext context) {
if(myList != null){
return myList[index].screen;
}else{
return null;
}
}));
},
child: Padding(
padding: EdgeInsets.all(3),
child: Card(
elevation: 10,
child: ListView(
children: <Widget>[
SizedBox(
height: 20,
),
Image.asset(
images[index],
height: 50.0,
width: 50.0,
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
services[index],
style: TextStyle(
fontSize: 16.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
),
color: Color(color),
),
),
);
},
),
),
);
}
}
class Items {
String title;
String subtitle;
String event;
String img;
final Widget screen;
Items({this.title, this.subtitle, this.event, this.img, this.screen});
}
my Nav bar code
class _NavSCreenState extends State<NavSCreen> {
final List<Widget> _screens = [Home()];
final List<IconData> _icons = const [
Icons.home,
Icons.settings,
MdiIcons.accountCircleOutline,
MdiIcons.accountGroupOutline,
Icons.menu,
];
int _selectedIndex = 0;
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _icons.length,
child: Scaffold(
body: IndexedStack(index: _selectedIndex, children: _screens),
bottomNavigationBar: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: CustomTabBar(
icons: _icons,
selectedIndex: _selectedIndex,
onTap: (index) => setState(() => _selectedIndex = index),
),
),
));
}
}
Try this by adding SingleChildScrollView. Hope this will solve your problem.
#override
Widget build(BuildContext context) {
List<Items> myList = [home, update, bluetooth, forms, supervisor, messages, settings, check, logout];
var color = 0xff453658;
return Scaffold(
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
height: 500,
// margin: EdgeInsets.only(top: 10),
// padding: EdgeInsets.all(20),
child: GridView.builder(
// add this
shrinkWrap: true,
itemCount: services.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: MediaQuery.of(context).size.width /
(MediaQuery.of(context).size.height / 1.4),
),
itemBuilder: (BuildContext context, int index) {
return GestureDetector(
onTap: () {
Navigator.push(context, new MaterialPageRoute<Widget>(
builder: (BuildContext context) {
if(myList != null){
return myList[index].screen;
}else{
return null;
}
}));
},
child: Padding(
padding: EdgeInsets.all(3),
child: Card(
elevation: 10,
child: ListView(
children: <Widget>[
SizedBox(
height: 20,
),
Image.asset(
images[index],
height: 50.0,
width: 50.0,
),
Padding(
padding: const EdgeInsets.all(20.0),
child: Text(
services[index],
style: TextStyle(
fontSize: 16.0,
height: 1.2,
color: Colors.white,
fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
],
),
color: Color(color),
),
),
);
},
),
),
),
),
);
}
You need to embed the GridView into a SingleChildScrollView widget. This widget handles the scrolling for its child, which is in your case the GridView. The same applies to ListView.
See the links for detailed documentation.
// ...
child: Container(
height: 500,
child: SingleChildScrollView(
child: GridView.builder(
// ...
)
)
)
// ...
EDIT
I forgot, that you have to give a GridView a height to work inside a SingleChildScrollView. You can use a Container that wraps the GridView.
// ...
child: Container(
height: 500,
child: SingleChildScrollView(
child: Container(
height: 500,
child: GridView.builder(
// ...
)
)
)
)
// ...
But with that approach you have to give your GridView a predefined height. An alternative is the CustomScrollView but you have to use a SliverGrid for that.
CustomScrollView(
slivers: [
SliverGrid(
// ...
)
]
)

How can I move the text composer to the bottom of the screen when using stack?

Does anyone know why I can't seem to move the text entry box (_buildTextComposer()) to the bottom of the page? I've tried everything and can't seem to get it to work...
Thanks!
I think it's mainly in this code but I've included all my code below:
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Stack(children: <Widget>[
_buildIamge(),
_buildTopHeader(),
Container(
alignment: Alignment.center,
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
Container(
decoration: new BoxDecoration(color: Theme.of(context).cardColor),
height: 50.0,
child: _buildTextComposer(),
alignment: Alignment.bottomCenter,
),
]),
resizeToAvoidBottomPadding:false,
);
}
}
Here is a picture of how it looks: App Example
import 'package:flutter/material.dart';
import 'package:flutter_dialogflow/dialogflow_v2.dart';
double _imageHeight = 256.0;
void main() => runApp(new Olivia());
class Olivia extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Example Dialogflow Flutter',
theme: new ThemeData(
primarySwatch: Colors.deepOrange,
),
debugShowCheckedModeBanner: false,
home: new HomePageDialogflow(),
);
}
}
class HomePageDialogflow extends StatefulWidget {
HomePageDialogflow({Key key, this.title}) : super(key: key);
final String title;
#override
_HomePageDialogflow createState() => new _HomePageDialogflow();
}
class _HomePageDialogflow extends State<HomePageDialogflow> {
final List<ChatMessage> _messages = <ChatMessage>[];
final TextEditingController _textController = new TextEditingController();
Widget _buildTextComposer() {
return new IconTheme(
data: new IconThemeData(color: Theme.of(context).accentColor),
child: new Container(
margin: const EdgeInsets.symmetric(horizontal: 8.0),
child: new Row(
children: <Widget>[
new Flexible(
child: new TextField(
controller: _textController,
onSubmitted: _handleSubmitted,
decoration:
new InputDecoration.collapsed(hintText: "Send a message"),
),
),
new Container(
margin: new EdgeInsets.symmetric(horizontal: 4.0),
child: new IconButton(
icon: new Icon(Icons.send),
onPressed: () => _handleSubmitted(_textController.text)),
),
],
),
),
);
}
void Response(query) async {
_textController.clear();
AuthGoogle authGoogle =
await AuthGoogle(fileJson: "assets/credentials.json")
.build();
Dialogflow dialogflow =
Dialogflow(authGoogle: authGoogle, language: Language.english);
AIResponse response = await dialogflow.detectIntent(query);
ChatMessage message = new ChatMessage(
text: response.getMessage() ??
new CardDialogflow(response.getListMessage()[0]).title,
name: "Bot",
type: false,
);
setState(() {
_messages.insert(0, message);
});
}
void _handleSubmitted(String text) {
_textController.clear();
ChatMessage message = new ChatMessage(
text: text,
name: "Promise",
type: true,
);
setState(() {
_messages.insert(0, message);
});
Response(text);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: new Stack(children: <Widget>[
_buildIamge(),
_buildTopHeader(),
Container(
alignment: Alignment.center,
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
Container(
decoration: new BoxDecoration(color: Theme.of(context).cardColor),
height: 50.0,
child: _buildTextComposer(),
alignment: Alignment.bottomCenter,
),
]),
resizeToAvoidBottomPadding:false,
);
}
}
class Conatiner {
}
class ChatMessage extends StatelessWidget {
ChatMessage({this.text, this.name, this.type});
final String text;
final String name;
final bool type;
List<Widget> otherMessage(context) {
return <Widget>[
new Container(
margin: const EdgeInsets.only(right: 16.0),
child: new CircleAvatar(child: new Text('B')),
),
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(this.name,
style: new TextStyle(fontWeight: FontWeight.bold)),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text),
),
],
),
),
];
}
List<Widget> myMessage(context) {
return <Widget>[
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
new Text(this.name, style: Theme.of(context).textTheme.subhead),
new Container(
margin: const EdgeInsets.only(top: 5.0),
child: new Text(text),
),
],
),
),
new Container(
margin: const EdgeInsets.only(left: 16.0),
child: new CircleAvatar(
child: new Text(
this.name[0],
style: new TextStyle(fontWeight: FontWeight.bold),
)),
),
];
}
#override
Widget build(BuildContext context) {
return new Container(
margin: const EdgeInsets.symmetric(vertical: 10.0),
child: new Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: this.type ? myMessage(context) : otherMessage(context),
),
);
}
}
Widget _buildIamge() {
return new ClipPath(
clipper: new DialogonalClipper(),
child: new Image.asset(
'assets/Header.png',
fit: BoxFit.cover,
height: _imageHeight,
),
);
}
class DialogonalClipper extends CustomClipper<Path> {
#override
Path getClip(Size size) {
Path path = new Path();
path.lineTo(0.0, size.height - 120.0);
path.lineTo(size.width, size.height-170);
path.lineTo(size.width, 0.0);
path.close();
return path;
}
#override
bool shouldReclip(CustomClipper<Path> oldClipper) => true;
}
Widget _buildTopHeader() {
return new Padding(
padding: new EdgeInsets.only(left: 16.0, top: 70.5),
child: new Row(
children: <Widget>[
new Padding(
padding: const EdgeInsets.only(left: 5.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Text(
'Olivia',
style: new TextStyle(
fontSize: 30.0,
color: Colors.white,
fontWeight: FontWeight.w700),
),
],
),
),
],
),
);
}
Just change your build method as follow,
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Expanded(
child: Stack(children: <Widget>[
_buildIamge(),
_buildTopHeader(),
Container(
alignment: Alignment.center,
child: new ListView.builder(
padding: new EdgeInsets.all(8.0),
reverse: true,
itemBuilder: (_, int index) => _messages[index],
itemCount: _messages.length,
)),
]),
),
Container(
decoration:
new BoxDecoration(color: Theme.of(context).cardColor),
height: 50.0,
child: _buildTextComposer(),
alignment: Alignment.bottomCenter,
),
],
),
),
);
}
Putting a Stack Widget Inside Column and wrapping it inside it will give the as much space as _buildTextComposer() require and set it to the bottom of the page.

How to add text along with carousel images in flutter?

I tried to add carousel along with text. But As far I can only add image carousel, Have no idea on how to add text. Please help me. Totally new.
I expect the output to be like image on above and text on below, but both need to swipe at same time.
I have no idea where to add the text field. I made this carousel with a example in youtube. But no example for carousel images with text. I tried something manually, But it all doesn't ended much well.
Please help me fix it. Thank-you
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Slider'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
PageController pageController;
//Images List
List<String> images = [
'',
];
#override
void initState() {
super.initState();
pageController = PageController(initialPage: 1, viewportFraction: 0.6);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: PageView.builder(
controller: pageController,
itemCount: images.length,
itemBuilder: (context, position) {
return imageSlider(position);
}
)
);
}
imageSlider(int index) {
return AnimatedBuilder(
animation: pageController,
builder: (context, widget) {
double value = 1;
if(pageController.position.haveDimensions){
value = pageController.page - index;
value = (1 - (value.abs() * 0.3.clamp(0.0, 1.0)));
}
return Center(
child: SizedBox(
height: Curves.easeInOut.transform(value) * 400.0,
width: Curves.easeInOut.transform(value) * 350.0,
child: widget,
),
);
},
child: Container(
margin: EdgeInsets.all(10.0),
child: Image.asset(images[index],fit: BoxFit.cover),
),
);
}
}
Use column instead of container, so just replace this:
child: Container(
margin: EdgeInsets.all(10.0),
child: Image.asset(images[index],fit: BoxFit.cover),
),
with this:
child: Column(
// To centralize the children.
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
// First child
Container(
margin: EdgeInsets.all(10.0),
child: Image.asset(images[index],fit: BoxFit.cover),
),
// Second child
Text(
'foo',
style: TextStyle(
// Add text's style here
),
),
]
),
OR instead of building your own carousal, you can use a ready to use one, e.g: carousel_slider or flutter_swiper
try this
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
heading,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
sub_heading,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
//textAlign: TextAlign.center,
),
),
],
),
PageView with Next and Previous Functionality
Step 1:- Add PageView widget
class _WalkThroughState extends State<WalkThrough> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
var height = 0.0;
var width = 0.0;
int mCurrentIndex = -1;
List<Widget> pages=[PageOne(message: "Beauty Trends",),PageTwo(message: "Exclusive Offers",),PageThree(message: "Make your Kit",)];
PageController _controller = new PageController();
static const _kDuration = const Duration(milliseconds: 300);
static const _kCurve = Curves.ease;
#override
void initState() {
super.initState();
_controller = PageController();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Scaffold(
extendBodyBehindAppBar: true,
body: Stack(
children: [
Container(
height: height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [startColorBackground, endColorBackground])),
),
Column(
children: <Widget>[
Flexible(
child: Container(
child: PageIndicatorContainer(
key: _scaffoldKey,
child: PageView.builder(
controller: _controller,
onPageChanged: _onPageViewChange,
itemBuilder: (context, position) {
mCurrentIndex = position;
return pages[position];
},
itemCount: 3,
),
align: IndicatorAlign.bottom,
length: 3,
indicatorSpace: 10.0,
indicatorColor: Colors.white,
indicatorSelectorColor: Colors.black,
)),
),
Container(
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
// ignore: invalid_use_of_protected_member
mCurrentIndex != 0 ?Padding(
padding: const EdgeInsets.only(left: 30.0, bottom: 30.0),
child: GestureDetector(
onTap: () {
_controller.previousPage(
duration: _kDuration, curve: _kCurve);
},
child: Text('Prev', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),)),
) : Container(),
mCurrentIndex != 2 ? Padding(
padding: const EdgeInsets.only(right: 30.0, bottom: 30.0),
child: GestureDetector(
onTap: () {
_controller.nextPage(
duration: _kDuration, curve: _kCurve);
},
child: Text('Next', style: TextStyle(fontSize: 20, fontWeight: FontWeight.w500),)),
) : Container(),
],
),
),
],
),
],
),
);
}
_onPageViewChange(int page) {
/*print("Current Page: " + page.toString());
int previousPage = page;
if(page != 0) previousPage--;
else previousPage = 2;
print("Previous page: $previousPage");*/
setState(() {
mCurrentIndex = page;
print(mCurrentIndex);
});
}
}
Step 2:- Add Pages with data
Page 1
class PageOne extends StatelessWidget {
final String message;
var height = 0.0;
var width = 0.0;
PageOne({Key key, #required this.message}) : super(key: key);
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
height: height - 50,
child: Align(alignment: Alignment.center, child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Container(
margin: EdgeInsets.only(top: 16.0),
child: Image(image: AssetImage("assets/images/banner_one.png"),)),
Container(
margin: EdgeInsets.only(bottom: 16.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(message, style: TextStyle(fontSize: 40, fontFamily: 'Playfair', fontWeight: FontWeight.bold),),
SizedBox(height: 30,),
Text("Lorem Ipsum is simply dummy text of the \n printing and typesetting industry.", textAlign: TextAlign.center, style: TextStyle(fontSize: 18),),
],
),
),
],
),),
);
}
}
Page 2
class PageTwo extends StatelessWidget {
final String message;
var height = 0.0;
var width = 0.0;
PageTwo({Key key, #required this.message}) : super(key: key);
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
child: Column(
children: [
Expanded(
flex: 2,
child: Container(
width: width,
child: Image(
width: double.infinity,
image: AssetImage("assets/images/banner_two.png"),
fit: BoxFit.cover,)),
),
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(top: 16),
child: Column(
children: [
SizedBox(
height: 40,
),
Text(message, style: TextStyle(fontSize: 40, fontFamily: 'Playfair', fontWeight: FontWeight.bold),),
SizedBox(height: 30,),
Text("Lorem Ipsum is simply dummy text of the \n printing and typesetting industry.", textAlign: TextAlign.center, style: TextStyle(fontSize: 18),),
],
),
),
),
],
),
);
}
}
Page 3
class PageThree extends StatelessWidget {
final String message;
var height = 0.0;
var width = 0.0;
PageThree({Key key, #required this.message}) : super(key: key);
#override
Widget build(BuildContext context) {
height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
flex: 3,
child: Container(
width: width,
child: Image( width: double.infinity,
image: AssetImage("assets/images/banner_three.png"), fit: BoxFit.fill,)),
),
Expanded(
flex: 1,
child: Container(
child: Column(
children: [
Text(message, style: TextStyle(fontSize: 40, fontFamily: 'Playfair', fontWeight: FontWeight.bold),),
SizedBox(height: 30,),
Text("Lorem Ipsum is simply dummy text of the \n printing and typesetting industry.", textAlign: TextAlign.center, style: TextStyle(fontSize: 18),),
],
),
),
),
],
),
);
}
}
You can add N number of pages. Right now am adding 3 pages with data
Colors.dart
import 'package:flutter/material.dart';
const viewColor = Color(0xFFF5D9CE);
const textPinkColor = Color(0xFFF51678);
const buttonPinkColor = Color(0xFFF5147C);
const pinkColor = Color(0xFFF51479);
const pinkBackground = Color(0xFFF5C3C7);
const startColorBackground = Color(0xFFF5F4F2);
const endColorBackground = Color(0xFFF5EAE6);
This is complete working code with Image on top with text and dots. For this you need to use these two libraries:- " carousel_slider: ^4.1.1 ", "smooth_page_indicator: ^1.0.0+2", update them to the latest.
class MyItem {
String itemName;
String path;
MyItem(this.itemName, this.path);
}
class craouselImage extends StatefulWidget {
#override
_craouselImage createState() => _craouselImage();
}
class _craouselImage extends State<craouselImage> {
int activeIndex = 0;
List<MyItem> items = [
MyItem("item 1", 'assets/images/appiconlogo.png'),
MyItem("item 2", 'assets/images/Mockup4.png'),
];
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
CarouselSlider.builder(
itemCount: items.length,
options: CarouselOptions(
height: 400,
viewportFraction: 1,
autoPlay: true,
enlargeCenterPage: true,
enlargeStrategy: CenterPageEnlargeStrategy.height,
autoPlayInterval: const Duration(seconds: 1),
onPageChanged: (index, reason) {
setState(() {
activeIndex = index;
});
},
),
itemBuilder: (context, index, realIndex) {
final imgList = items[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Expanded(child: buildImage(imgList.path, index)),
const SizedBox(
height: 15,
),
buildText(imgList.itemName, index),
],
);
},
),
const SizedBox(
height: 22,
),
buildIndicator(),
const SizedBox(
height: 22,
),
//buildText(itemName, index),
// buildText(),
],
),
);
}
Widget buildImage(String imgList, int index) => Container(
margin: const EdgeInsets.symmetric(horizontal: 12),
color: Colors.transparent,
child: Align(
alignment: Alignment.center,
child: Image.asset(
imgList,
fit: BoxFit.cover,
),
),
);
buildIndicator() => AnimatedSmoothIndicator(
activeIndex: activeIndex,
count: items.length,
effect: const JumpingDotEffect(
dotColor: Colors.black,
dotHeight: 15,
dotWidth: 15,
activeDotColor: mRed),
);
buildText(String itemName, int index) => Align(
alignment: FractionalOffset.bottomCenter,
child: Text(
itemName,
style: const TextStyle(
fontWeight: FontWeight.w700, fontSize: 23, color: mRed),
));
}