Related
I want to make a view where there will be a container with some data and below that a list of some other data. And I want both of them to scroll together. So for that I use a singlechildscrollview (physics: ScrollPhysics(),) inside that I used a column and inside column I used the container and a listview builder(shrinkWrap: true,physics: NeverScrollableScrollPhysics(),). But when did so I got an exception error.
**
FlutterError (RenderFlex children have non-zero flex but incoming height constraints are unbounded.
When a column is in a parent that does not provide a finite height constraint, for example if it is in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the vertical direction.
**
Then I tried the same code after wraping builder with Expended(). I got this error.
**
FlutterError (RenderFlex children have non-zero flex but incoming height constraints are unbounded.
When a column is in a parent that does not provide a finite height constraint, for example if it is in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the vertical direction.
**
** MY Code **
import 'package:Healthwise/helpers/dataVariables.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:get/get_navigation/get_navigation.dart';
import '../helpers/backEnd.dart';
import '../helpers/frontEnd.dart';
class ResultPage extends StatefulWidget {
const ResultPage({Key? key}) : super(key: key);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
// String docId = '';
String objectToString = '';
// List of string for storing..
var dataAsString = <String>[];
#override
void initState() {
super.initState();
// getUsers();
getUserById();
}
getUserById() {
String id = itemName.toLowerCase().trim();
fruitInfoDoc.doc(id).get().then((DocumentSnapshot doc) {
// final x = doc.data();
// docId= doc.id;
objectToString = doc.data().toString();
String temp = '';
// print(doc.data());
// print(doc.id);
int i = 1;
bool end = false;
//We are just parsing the object into string.
while (objectToString[i] != '}') {
if (objectToString[i - 1] == ' ' && objectToString[i - 2] == ':') {
while (objectToString[i] != ',' && end != true) {
temp += objectToString[i];
if (objectToString[i + 1] != '}') {
i++;
} else {
end = true;
}
}
//Here I add all the strings to list...
// This line works fine.
dataAsString.add(temp);
temp = '';
print("The code below this line prints everything perfectly");
print(dataAsString.length);
print(dataAsString);
}
i++;
}
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
return false;
},
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
backgroundColor: primary_color,
title: Center(
child: Text(
itemName.trim().toUpperCase(),
style: TextStyle(
//Fruit Name
color: Color.fromARGB(255, 255, 255, 255),
fontSize: 15),
),
)),
body: SingleChildScrollView(
physics: ScrollPhysics(),
child: Column(
children: [
Container(
color: Color.fromARGB(255, 150, 50, 50),
height: 200,
width: 100,
),
Expanded(
child: Expanded(
child: Builder(
builder: (context) {
if (dataAsString.length > 0) {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: dataAsString.length,
itemBuilder: (BuildContext context, int index) {
return EditedListTile(
dataAsString: dataAsString,
index: index,
);
});
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
),
),
],
),
),
),
);
}
}
Since I couldn't use your code to debug, here is something similar to what you're trying to do. You were getting that error because you didn't have your Expanded widgets in correct place.
You have you're entire page scrollable with container inside that has scrollable Listview or remove Listview and add other widget at is place.
Below that you have another widget scrollable Listview, you can replace that with other widget and but keep Expanded widget as it is.
For more info on Expanded Widget
class ResultPage extends StatefulWidget {
const ResultPage({Key? key}) : super(key: key);
#override
State<ResultPage> createState() => _ResultPageState();
}
class _ResultPageState extends State<ResultPage> {
// String docId = '';
String objectToString = '';
// List of string for storing..
List<String> list = List<String>.generate(100, (counter) => "Item $counter");
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
Navigator.pop(context);
return false;
},
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Center(
child: Text(
'itemName'.trim().toUpperCase(),
style: TextStyle(
//Fruit Name
color: Color.fromARGB(255, 255, 255, 255),
fontSize: 15),
),
),
),
body: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height * 1,
child: Column(
children: [
Expanded(
child: Container(
color: Color.fromARGB(255, 150, 50, 50),
width: 100,
child: ListView.builder(
// physics: NeverScrollableScrollPhysics(), // Uncomment this to stop scroll
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Text(list[index]);
},
),
),
),
Expanded(
child: ListView.builder(
// physics: NeverScrollableScrollPhysics(), // Uncomment this to stop scroll
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Text(list[index]);
},
),
),
],
),
),
),
),
);
}
}
When the scrollDirection is set to vertical, it works as expected. The problem is when I set the section.axis to Axis.horizontal so that the ListView displays the widgets horizontally.
This problem wont solve using Flexible or Expanded widget, because the the height of the ListView needs to be defined by the widgets in the list.
As you can see shrinkWrap is also enabled. So I dont know wth is going on here, thanks for helping.
Console says:
'constraints.hasBoundedHeight': is not true.
The relevant error-causing widget was: ListView
class SectionWidget extends StatelessWidget {
final Section section;
const SectionWidget({#required this.section});
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(section.title),
ListView.separated(
shrinkWrap: true,
scrollDirection: section.axis,
physics: section.axis == Axis.vertical
? NeverScrollableScrollPhysics()
: null,
itemCount: section.itemList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
width: 100,
color: Colors.red,
); // Just to test if it works
},
separatorBuilder: (BuildContext context, int index) {
double paddingBetween = 10;
if (section.axis == Axis.horizontal) {
return SizedBox(width: paddingBetween);
} else {
return SizedBox(height: paddingBetween);
}
},
),
],
);
}
}
That's because Column or Row gives as much height/width that their children need and ListView takes as much height/width available from its parent.
To fix this, just wrap ListView in a Container. Like this:
import 'package:flutter/material.dart';
class SectionWidget extends StatelessWidget {
final Section section;
const SectionWidget({#required this.section});
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(section.title),
Container(
height: section.axis == Axis.horizontal ? 100 : 700, // I just set these values
width: section.axis == Axis.horizontal ? 350 : 100, // to fit with my device.
child: ListView.separated( // If you want to fit for
shrinkWrap: true, // all devices, use MediaQuery
scrollDirection: section.axis,
physics: section.axis == Axis.vertical
? NeverScrollableScrollPhysics()
: null,
itemCount: section.itemList.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: 100,
width: 100,
color: Colors.red,
); // Just to test if it works
},
separatorBuilder: (BuildContext context, int index) {
double paddingBetween = 10;
if (section.axis == Axis.horizontal) {
return SizedBox(width: paddingBetween);
} else {
return SizedBox(height: paddingBetween);
}
},
),
),
],
);
}
}
For more info about MediaQuery
Edit:
I think using a gridview would be more suited for this. I've remade the build code for ya to suit different children's sizes. The positioning of the children and other stuff I think you can manage.
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Expanded(
child: Text(section.title),
),
SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: GridView.builder(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 1),
shrinkWrap: true,
scrollDirection: section.axis,
physics: section.axis == Axis.vertical
? NeverScrollableScrollPhysics()
: null,
itemCount: section.itemList.length,
itemBuilder: (context, index) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
// Spacer(),
Container(
margin: EdgeInsets.all(10),
height: 100,
width: 100,
color: Colors.red,
),
// Spacer(),
],
);
},
),
),
],
);
}
I have an Image Slider / Carousel, but it won't show a large / full image as I want. It only shows a half image and its contain a shadow border in it...
Here is what I've done:
Here is the view that I hope I can make:
I've 2 dart files.
here are the one who calls it:
final List<String> imgList = [
'images/Polo 01.png',
'images/Polo 02.png',
'images/Polo 03.png',
'images/Polo 04.png',
'images/Polo 05.png',
];
final List child = map<Widget>(
imgList,
(index, i) {
return Container(
margin: EdgeInsets.all(5.0),
child: ClipRRect(
child: Stack(children: <Widget>[
Image.asset(i, fit: BoxFit.cover, width: 1000.0),
Positioned(
bottom: 0.0,
left: 0.0,
right: 0.0,
child: Container(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
),
),
]),
),
);
},
).toList();
List<T> map<T>(List list, Function handler) {
List<T> result = [];
for (var i = 0; i < list.length; i++) {
result.add(handler(i, list[i]));
}
return result;
}
class CarouselWithIndicator extends StatefulWidget {
#override
_CarouselWithIndicatorState createState() => _CarouselWithIndicatorState();
}
class _CarouselWithIndicatorState extends State<CarouselWithIndicator> {
int _current = 0;
#override
Widget build(BuildContext context) {
return Column(children: [
CarouselSlider(
items: child,
autoPlay: true,
enlargeCenterPage: false,
aspectRatio: 2.0,
onPageChanged: (index) {
setState(() {
_current = index;
});
},
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: map<Widget>(
imgList,
(index, url) {
return Container(
width: 8.0,
height: 8.0,
margin: EdgeInsets.symmetric(vertical: 10.0, horizontal: 2.0),
);
},
),
),
]);
}
}
and here to show the view:
body: ListView (
children: <Widget>[
new Align
(
alignment: Alignment.topCenter,
child: Container(
padding: const EdgeInsets.all(5.0),
child: Text('Nama Produk', style: TextStyle(color: Colors.black)),
)
Padding( //I M A G E - S L I D E R
padding: EdgeInsets.symmetric(vertical: 15.0),
child: Column(children: [
CarouselWithIndicator(),
])
),
I've 3 questions.
how to make full image like no. 3 ?
how to create a table like no. 2 ?
how to make a different background color / give a background at table like no.1 ?
Your map method is unnecessary you can do that easier like this:
final List<Color> colorList = [
Colors.blue,
Colors.red,
Colors.green,
Colors.deepPurple,
Colors.yellow,
];
final List<Widget> colorBackgrounds = colorList
.map((color) => Container(
margin: EdgeInsets.all(5.0),
child: Container(
width: 500,
height: 500,
color: color,
child: Text("Hello"),
),
))
.toList();
The above code should tell you how to set a background color.
In terms of showing a "full image" you should look at the CarouselSlider's aspectRatio property. Here's a hint width/height.
For the table consider creating a widget tree like this:
Column
Row
Text
Expanded
Text
Row
...
Alternatively look into Table, TableRow and TableCell.
I'm using Flutter's SliverAppBar with SliverList.
The app bar works fine with long list, that scroll a lot.
However, if I have medium size list with 8 items the app bar only partially collapses until the list runs out of items. It makes logical sense that the scroll stops because there are no more items but it leaves a really nasty effect on the app bar, which is being left in the middle of its transition in to collapsed toolbar.
Is there a way to force the list to scroll up until the toolbar is fully collapsed?
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
label: Text("Start!"),
icon: Icon(Icons.play_arrow),
backgroundColor: Colors.orange,
elevation: 12,
onPressed: () {
Routing.navigate(
context,
LoggingPage(
workout: _workout,
exercises: workoutExercises,
),
);
},
),
body: CustomScrollView( physics: ScrollPhysics(),
slivers: <Widget>[
SliverAppBar(
actions: <Widget>[
MaterialButton(onPressed: (){}, child: Text("data"),)
],
expandedHeight: 300,
pinned: true,
floating: true,
snap: true,
flexibleSpace: FlexibleSpaceBar(
title: Text(_workout.name),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
buildSliverListItem,
childCount: workoutExercises.length,
),
),
],
),
);
}
We can use NestedScrollView, SliverOverlapAbsorber and SliverOverlapInjector based on Code With Andrea's example here
https://github.com/bizz84/slivers_demo_flutter/blob/master/lib/pages/nested_scroll_view_page.dart.
We use a NestedScrollView. First, we embed the SliverAppbar within the headerSliverBuilder with a SliverOverlapAbsorber above the SliverAppBar.
Next, we embed the CustomScrollView within a builder inside the body of the NestedScrollView. We add a SliverOverlapInjector at the top of the body.
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
return <Widget>[
SliverOverlapAbsorber(
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
pinned: true,
//floating: true,
stretch: true,
expandedHeight: 300.0,
flexibleSpace: FlexibleSpaceBar(
centerTitle: true,
title: const Text('Weather Report'),
background: Image.asset(
'assets/images/logo1.jpg',
fit: BoxFit.cover,
),
),
),
),
];
},
body: SafeArea(
child: Builder(
builder:(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverOverlapInjector(
// This is the flip side of the SliverOverlapAbsorber above.
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int i){
return ListTile(
leading: Icon(Icons.wb_sunny),
title: i%2 != 1 ? Text('Sunday ${i+1}') : Text('Monday ${i+1}'),
subtitle: Text('sunny, h: 80, l: 65'),
);
},
childCount: 5
),
),
],
);
}
),
),
),
);
As a workaround you can use widget with custom RenderSliver. It must be added to the end of a slivers list.
class CustomRenderSliver extends RenderSliver {
final double _minHeaderHeight;
final double _maxHeaderHeight;
CustomRenderSliver(this._minHeaderHeight, this._maxHeaderHeight);
#override
void performLayout() {
double maxHeight = this.constraints.viewportMainAxisExtent -
(this.constraints.precedingScrollExtent - _maxHeaderHeight) /*height of regular list elements*/ -
_minHeaderHeight;
if (maxHeight < 0.0) maxHeight = 0.0;
this.geometry = SliverGeometry(scrollExtent: maxHeight);
}
}
list with custom sliver
Complete code
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
final minHeaderHeight = 90.0;
final maxHeaderHeight = 180.0;
List<Widget> slivers = List.generate(4, (index) {
return SliverToBoxAdapter(
child: SizedBox(
height: 100,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 4),
child: Container(
color: Colors.blue,
),
),
),
);
});
// header
slivers.insert(
0, SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: minHeaderHeight,
maxHeight: maxHeaderHeight
),
));
// custom sliver
slivers.add(CustomRenderSliverWidget(minHeaderHeight, maxHeaderHeight));
runApp(MaterialApp(
home: CustomScrollView(
slivers: slivers,
),
));
}
class CustomRenderSliverWidget extends LeafRenderObjectWidget {
final double _minHeaderHeight;
final double _maxHeaderHeight;
CustomRenderSliverWidget(this._minHeaderHeight, this._maxHeaderHeight);
#override
RenderObject createRenderObject(BuildContext context) {
return CustomRenderSliver(_minHeaderHeight, _maxHeaderHeight);
}
}
class CustomRenderSliver extends RenderSliver {
final double _minHeaderHeight;
final double _maxHeaderHeight;
CustomRenderSliver(this._minHeaderHeight, this._maxHeaderHeight);
#override
void performLayout() {
double maxHeight = this.constraints.viewportMainAxisExtent -
(this.constraints.precedingScrollExtent - _maxHeaderHeight) /*height of regular list elements*/ -
_minHeaderHeight;
if (maxHeight < 0.0) maxHeight = 0.0;
this.geometry = SliverGeometry(scrollExtent: maxHeight);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
#required this.minHeight,
#required this.maxHeight,
});
final double minHeight;
final double maxHeight;
#override
double get minExtent => minHeight;
#override
double get maxExtent => max(maxHeight, minHeight);
#override
Widget build(BuildContext context, double shrinkOffset,
bool overlapsContent) {
return Container(color: Colors.red,);
}
#override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight;
}
}
I Am trying to have a horizontal ListView Widget that magnifies the center items. I tried using the normal ListView but I couldn't get the center items to magnify. Then while searching the flutter docs I came across ListWheelScrollView but unfortunately, it doesn't seem to support horizontal children layout. So basically am looking to create a horizontal ListView with center items magnification. I'd appreciate it if anyone can at least point me in the right direction. Thanks
Edit:
I have published package based on this.
pub.dev/packages/list_wheel_scroll_view_x
Here's my workaround.
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class ListWheelScrollViewX extends StatelessWidget {
final Widget Function(BuildContext, int) builder;
final Axis scrollDirection;
final FixedExtentScrollController controller;
final double itemExtent;
final double diameterRatio;
final void Function(int) onSelectedItemChanged;
const ListWheelScrollViewX({
Key key,
#required this.builder,
#required this.itemExtent,
this.controller,
this.onSelectedItemChanged,
this.scrollDirection = Axis.vertical,
this.diameterRatio = 100000,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return RotatedBox(
quarterTurns: scrollDirection == Axis.horizontal ? 3 : 0,
child: ListWheelScrollView.useDelegate(
onSelectedItemChanged: onSelectedItemChanged,
controller: controller,
itemExtent: itemExtent,
diameterRatio: diameterRatio,
physics: FixedExtentScrollPhysics(),
childDelegate: ListWheelChildBuilderDelegate(
builder: (context, index) {
return RotatedBox(
quarterTurns: scrollDirection == Axis.horizontal ? 1 : 0,
child: builder(context, index),
);
},
),
),
);
}
}
You can do this using the built-in ListWheelScrollView by pairing it with the Rotated Box. This is kind of a hack which works.
RotatedBox(
quarterTurns: -1,
child: ListWheelScrollView(
onSelectedItemChanged: (x) {
setState(() {
selected = x;
});
},
controller: _scrollController,
children: List.generate(
itemCount,
(x) => RotatedBox(
quarterTurns: 1,
child: AnimatedContainer(
duration: Duration(milliseconds: 400),
width: x == selected ? 60 : 50,
height: x == selected ? 60 : 50,
alignment: Alignment.center,
decoration: BoxDecoration(
color: x == selected ? Colors.red : Colors.grey,
shape: BoxShape.circle),
child: Text('$x')))),
itemExtent: itemWidth,
)),
);
Full source Code here
I recommend using this approach until this issue is resolved
Heres the output
copy this code and used it
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class ListWheelScrollViewX extends StatelessWidget {
final Axis scrollDirection;
final List<Widget>? children;
final ScrollController? controller;
final ScrollPhysics? physics;
final double diameterRatio;
final double perspective;
final double offAxisFraction;
final bool useMagnifier;
final double magnification;
final double overAndUnderCenterOpacity;
final double itemExtent;
final double squeeze;
final ValueChanged<int>? onSelectedItemChanged;
final bool renderChildrenOutsideViewport;
final ListWheelChildDelegate? childDelegate;
final Clip clipBehavior;
const ListWheelScrollViewX({
Key? key,
this.scrollDirection = Axis.vertical,
this.controller,
this.physics,
this.diameterRatio = RenderListWheelViewport.defaultDiameterRatio,
this.perspective = RenderListWheelViewport.defaultPerspective,
this.offAxisFraction = 0.0,
this.useMagnifier = false,
this.magnification = 1.0,
this.overAndUnderCenterOpacity = 1.0,
required this.itemExtent,
this.squeeze = 1.0,
this.onSelectedItemChanged,
this.renderChildrenOutsideViewport = false,
this.clipBehavior = Clip.hardEdge,
required this.children,
}) : childDelegate = null,
super(key: key);
const ListWheelScrollViewX.useDelegate({
Key? key,
this.scrollDirection = Axis.vertical,
this.controller,
this.physics,
this.diameterRatio = RenderListWheelViewport.defaultDiameterRatio,
this.perspective = RenderListWheelViewport.defaultPerspective,
this.offAxisFraction = 0.0,
this.useMagnifier = false,
this.magnification = 1.0,
this.overAndUnderCenterOpacity = 1.0,
required this.itemExtent,
this.squeeze = 1.0,
this.onSelectedItemChanged,
this.renderChildrenOutsideViewport = false,
this.clipBehavior = Clip.hardEdge,
required this.childDelegate,
}) : children = null,
super(key: key);
#override
Widget build(BuildContext context) {
final _childDelegate = children != null
? ListWheelChildListDelegate(
children: children!.map((child) {
return RotatedBox(
quarterTurns: scrollDirection == Axis.horizontal ? 1 : 0,
child: child,
);
}).toList())
: ListWheelChildBuilderDelegate(
builder: (context, index) {
return RotatedBox(
quarterTurns: scrollDirection == Axis.horizontal ? 1 : 0,
child: childDelegate!.build(context, index),
);
},
);
return RotatedBox(
quarterTurns: scrollDirection == Axis.horizontal ? 3 : 0,
child: ListWheelScrollView.useDelegate(
controller: controller,
physics: FixedExtentScrollPhysics(),
diameterRatio: diameterRatio,
perspective: perspective,
offAxisFraction: offAxisFraction,
useMagnifier: useMagnifier,
magnification: magnification,
overAndUnderCenterOpacity: overAndUnderCenterOpacity,
itemExtent: itemExtent,
squeeze: squeeze,
onSelectedItemChanged: onSelectedItemChanged,
renderChildrenOutsideViewport: renderChildrenOutsideViewport,
clipBehavior: clipBehavior,
childDelegate: _childDelegate,
),
);
}
}
Example
ListWheelScrollViewX(
scrollDirection: Axis.horizontal,
itemExtent: 120,
children:...
),
Reference
list_wheel_scroll_view_x
changes:
convert to null safety
You can use this flutter package https://pub.dev/packages/carousel_slider.
It also has a very helpful description and few samples to see how it looks. And it's compatible with dart 2.0 too.
You can make this work with the help of ListView and PageView along with NotificationListener.
Below is my code for the same-
import 'dart:math';
import 'package:flutter/material.dart';
const SCALE_FRACTION = 0.9;
const FULL_SCALE = 1.0;
final PAGER_HEIGHT = SizeConfig.screenHeight*0.32;
const PAGER_WIDTH = double.infinity;
class PaymentWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _PaymentState();
}
class _PaymentState extends State<PaymentWidget> {
double viewPortFraction = 0.9;
int currentPage = 1;
double page = 2.0;
PageController pageController;
final List<String> _cardsImages = ['image/path1', 'image/path2',
'image/path3', 'image/path4'];
#override
void initState() {
pageController = PageController(
initialPage: currentPage, viewportFraction: viewPortFraction);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: null,
body: _creditCardsList()
);
}
Widget _creditCardsList() {
return ListView(
shrinkWrap: true,
children: <Widget>[
Container(
height: PAGER_HEIGHT,
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
if (notification is ScrollUpdateNotification) {
setState(() {
page = pageController.page;
});
}
},
child: PageView.builder(
onPageChanged: (pos) {
setState(() {
currentPage = pos;
});
},
physics: BouncingScrollPhysics(),
controller: pageController,
itemCount: _cardsImages.length,
itemBuilder: (context, index) {
final scale =
max(SCALE_FRACTION, (FULL_SCALE - (index - page).abs()) + viewPortFraction);
return CreditCardTile(
_cardsImages[index], scale);
},
),
),
),
],
);
}
Widget CreditCardTile(String image, double scale) {
return Align(
alignment: Alignment.bottomCenter,
child:Container(
height: PAGER_HEIGHT * scale,
width: PAGER_WIDTH * scale,
child: Card(
elevation: 5,
shadowColor: constColors.blueWhiteShade,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0)
),
clipBehavior: Clip.antiAlias,
child: Image.asset(
image,
fit: BoxFit.cover,
),
)
) ,
);
}
Add 2 RotatedBox as Follows
StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance
.collection('Categories')
.doc('EcomCat')
.snapshots(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.data == null) {
return Center(
child: CircularProgressIndicator(),
);
}
final DocumentSnapshot document = snapshot.data!;
final Map<String, dynamic> documentData =
document.data() as Map<String, dynamic>;
final List Category = documentData['category'];
return RotatedBox(quarterTurns: 1,
child: ListWheelScrollView.useDelegate(magnification: 200,
itemExtent: 180,
childDelegate: ListWheelChildBuilderDelegate(
childCount: Category.length,
builder: (context,index){
return Row(
children: [
RotatedBox(quarterTurns: -1,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: EdgeInsets.all(10),
shadowColor: Colors.black,
primary: Colors.teal,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(18))),
onPressed: () {
setState(() {
categoryVal =
Category[index].toString();
});
},
child: Text(
Category[index].toString(),
style: themeData.textTheme.headline4,
),
),
),
],
);
},
)),
);
},
),
Transform.rotate(
angle: -math.pi / 2,
child: ListWheelScrollView()
}
use Transform.rotate