Flutter Listview inside column not taking full height - flutter

Above one is requirement. Actually requirement is that first widget (Vertical List header with below list view should take full height) means if list view has 18 items. It should show 18 items. Then below that it should show horizontal scroll.
I tried in my way but due to column list view taking same height as other element due to which its not showing all item all the way. It takes half of height of screen and user need to scroll in that height itself.
Need your help to sort out it. As first listview should take full height and second widget should come below that.
Please see below code.
import 'dart:math';
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Flutter test",
style: TextStyle(color: Colors.black),
),
elevation: 5,
backgroundColor: Colors.white,
),
body: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
children: [
ListHeader("Vertical List Header"),
VerticalList(),
ListHeader("Horizontal List Header"),
HorizontalList(),
ListHeader("Vertical List Header"),
VerticalList(),
ScrollUp()
],
),
);
}
}
class ScrollUp extends StatelessWidget {
const ScrollUp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return InkWell(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
height: 50,
child: Center(
child: Text(
"Click to scroll up",
style: TextStyle(
fontSize: 18,
),
),
),
),
);
}
}
class ListHeader extends StatelessWidget {
final String title;
const ListHeader(String title) : title = title;
#override
Widget build(BuildContext context) {
return Text(
title,
style: TextStyle(fontSize: 18),
);
}
}
class HorizontalList extends StatelessWidget {
const HorizontalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 30,
itemBuilder: (BuildContext context, int index) => Container(
margin:
const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
width: 30,
height: 20,
color: Colors.grey,
)),
);
}
}
class VerticalList extends StatelessWidget {
const VerticalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Expanded(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx, int) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
width: double.infinity,
height: 50,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
);
},
itemCount: 8,
),
);
}
}

Change the Column widget with a ListView widget.
And add shrinkWrap: true to its child ListView's'.
Remove the Expanded widget on both ListView.Builder
The horizontal ListView.Builder must have a Fixed height ( Link )
Add physics: NeverScrollableScrollPhysics() to the vertical ListView.Builder
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Flutter test",
style: TextStyle(color: Colors.black),
),
elevation: 5,
backgroundColor: Colors.white,
),
body: ListView(
children: [
ListHeader("Vertical List Header"),
VerticalList(),
ListHeader("Horizontal List Header"),
HorizontalList(),
ListHeader("Vertical List Header"),
VerticalList(),
ScrollUp()
],
),
);
}
}
class ScrollUp extends StatelessWidget {
const ScrollUp({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return InkWell(
child: Container(
alignment: Alignment.bottomCenter,
width: double.infinity,
height: 50,
child: Center(
child: Text(
"Click to scroll up",
style: TextStyle(
fontSize: 18,
),
),
),
),
);
}
}
class ListHeader extends StatelessWidget {
final String title;
const ListHeader(String title) : title = title;
#override
Widget build(BuildContext context) {
return Text(
title,
style: TextStyle(fontSize: 18),
);
}
}
class HorizontalList extends StatelessWidget {
const HorizontalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 400,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 30,
itemBuilder: (BuildContext context, int index) => Container(
margin:
const EdgeInsets.symmetric(vertical: 20, horizontal: 10),
width: 30,
height: 20,
color: Colors.grey,
)),
);
}
}
class VerticalList extends StatelessWidget {
const VerticalList({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (ctx, int) {
return Container(
margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 20),
width: double.infinity,
height: 50,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
);
},
itemCount: 8,
);
}
}

This is my solution for same kind of problem.
import 'package:flutter/material.dart';
class MealDetailsScreen extends StatelessWidget {
Widget buildSectionTitle(BuildContext context, String title) {
return Container(
margin: EdgeInsets.symmetric(vertical: 10),
child: Text(
title,
style: Theme.of(context).textTheme.bodyText1,
),
);
}
Widget buildContainer({Widget child}) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(10)),
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
height: 300,
width: 300,
child: child,
);
}
#override
Widget build(BuildContext context) {
final mealId = ModalRoute.of(context).settings.arguments;
final selectedMeal =
DUMMY_MEALS.firstWhere((element) => element.id == mealId);
return Scaffold(
appBar: AppBar(
title: Text('${selectedMeal.title}'),
),
body: SingleChildScrollView(
child: Column(
children: [
Container(
height: 300,
width: double.infinity,
child: Image.network(
selectedMeal.imageUrl,
fit: BoxFit.cover,
),
),
buildSectionTitle(context, 'Ingredients'),
buildContainer(
child: ListView.builder(
itemBuilder: (ctx, index) => Card(
color: Theme.of(context).accentColor,
child: Padding(
padding:
const EdgeInsets.symmetric(vertical: 5, horizontal: 10),
child: Text(selectedMeal.ingredients[index]),
),
),
itemCount: selectedMeal.ingredients.length,
),
),
buildSectionTitle(context, 'Steps'),
buildContainer(
child: ListView.builder(
itemBuilder: (ctx, index) => Column(
children: [
ListTile(
leading: CircleAvatar(
child: Text('# ${(index + 1)}'),
),
title: Text(selectedMeal.steps[index]),
),
Divider(),
],
),
itemCount: selectedMeal.steps.length,
),
),
],
),
),
);
}
}

Related

How to zoom an item of a list on mouse-over, keeping it always visible (Flutter on Web platform)

The problem is described like this.
In a web environment, I have to build a horizontal list of images (like in Netflix) which should increase the size of the element when the user positions the mouse cursor over them. To achieve this, I'm using a Stack (with clipBehavior equals to Clip.none) to render each item in the list, when I detect the mouse-over event I add a new Container (larger than the size of the original item) to draw an AnimatedContainer inside which will grow to fill it.
The animation works great, but the container gets positioned down to the next right item on the list, however, I need it above the item.
Here is the code:
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 createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final double zoomTargetHeight = 320;
final double zoomTargetWidth = 500;
final double zoomOriginalHeight = 225;
final double zoomOriginalWidth = 400;
double _zoomHeight = 225;
double _zoomWidth = 400;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: SingleChildScrollView(
child: Column(
children: [
Image.network("https://source.unsplash.com/random/1600x900?cars"),
Container(
color: Colors.black87,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 12,
),
const Text(
"List of items",
style: TextStyle(color: Colors.white),
),
const SizedBox(
height: 12,
),
SizedBox(
height: 235,
child: ListView.separated(
clipBehavior: Clip.none,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return buildCard(index);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 12,
);
},
itemCount: 10,
),
),
const SizedBox(
height: 200,
),
],
),
),
),
],
),
),
);
}
Map _showZoom = {};
Widget buildCard(int index) {
Stack stack = Stack(
clipBehavior: Clip.none,
children: [
MouseRegion(
onEnter: (event) {
setState(() {
_showZoom["$index"] = true;
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
Image.network(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
Container(
color: Colors.black.withAlpha(100),
height: zoomOriginalHeight,
width: zoomOriginalWidth,
),
],
),
),
),
if (_showZoom["$index"] != null && _showZoom["$index"]!)
Positioned(
left: (zoomOriginalWidth - zoomTargetWidth) / 2,
top: (zoomOriginalHeight - zoomTargetHeight) / 2,
child: MouseRegion(
onHover: (_) {
setState(() {
_zoomHeight = zoomTargetHeight;
_zoomWidth = zoomTargetWidth;
});
},
onExit: (event) {
setState(() {
_showZoom["$index"] = false;
_zoomHeight = zoomOriginalHeight;
_zoomWidth = zoomOriginalWidth;
});
},
child: SizedBox(
width: zoomTargetWidth,
height: zoomTargetHeight,
child: Center(
child: AnimatedContainer(
duration: const Duration(milliseconds: 400),
width: _zoomWidth,
height: _zoomHeight,
// color: Colors.green.withAlpha(100),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
image: DecorationImage(
image: NetworkImage(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
fit: BoxFit.cover,
),
),
),
),
),
),
),
],
);
return stack;
}
}
Remember flutter config --enable-web
I think this is precisely what you are looking for (Check also the live demo on DartPad):
The solution is:
Use an outer Stack that wraps the ListView;
Add another ListView in front of it in the Stack with the same number of items and same item sizes;
Then, ignore the pointer-events with IgnorePointer on this new ListView so the back one will receive the scroll/tap/click events;
Synchronize the scroll between the back ListView and the front one by listening to scroll events with NotificationListener<ScrollNotification>;
Here's the code
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 createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final double zoomTargetHeight = 320;
final double zoomTargetWidth = 500;
final double zoomOriginalHeight = 225;
final double zoomOriginalWidth = 400;
late final ScrollController _controllerBack;
late final ScrollController _controllerFront;
#override
void initState() {
super.initState();
_controllerBack = ScrollController();
_controllerFront = ScrollController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Image.network("https://source.unsplash.com/random/1600x900?cars"),
Container(
color: Colors.black87,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 12,
),
const Text(
"List of items",
style: TextStyle(color: Colors.white),
),
const SizedBox(
height: 12,
),
SizedBox(
height: 225,
child: NotificationListener<ScrollNotification>(
onNotification: (notification) {
_controllerFront.jumpTo(_controllerBack.offset);
return true;
},
child: Stack(
clipBehavior: Clip.none,
children: [
ListView.separated(
controller: _controllerBack,
clipBehavior: Clip.none,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return buildBackCard(index);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 12,
);
},
itemCount: 10,
),
IgnorePointer(
child: ListView.separated(
controller: _controllerFront,
clipBehavior: Clip.none,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return buildFrontCard(index);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 12,
);
},
itemCount: 10,
),
),
],
),
),
),
const SizedBox(
height: 200,
),
],
),
),
),
],
),
),
);
}
final Map _showZoom = {};
Widget buildBackCard(int index) {
return MouseRegion(
onEnter: (event) {
setState(() {
_showZoom["$index"] = true;
});
},
onExit: (event) {
setState(() {
_showZoom["$index"] = false;
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
Image.network(
"https://source.unsplash.com/random/400x225?sig=$index&cars",
),
Container(
color: Colors.black.withAlpha(100),
height: zoomOriginalHeight,
width: zoomOriginalWidth,
),
],
),
),
);
}
Widget buildFrontCard(int index) {
Widget child;
double scale;
if (_showZoom["$index"] == null || !_showZoom["$index"]!) {
scale = 1;
child = SizedBox(
height: zoomOriginalHeight,
width: zoomOriginalWidth,
);
} else {
scale = zoomTargetWidth / zoomOriginalWidth;
child = Stack(
clipBehavior: Clip.none,
children: [
Container(
height: zoomOriginalHeight,
width: zoomOriginalWidth,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20.0),
image: DecorationImage(
image: NetworkImage(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
fit: BoxFit.cover,
),
),
),
],
);
}
return AnimatedScale(
duration: const Duration(milliseconds: 400),
scale: scale,
child: child,
);
}
}
I'd do something different. Instead of Stacking the zoomed-out and zoomed-in images it could be just one image with a AnimatedScale to do the transitions.
Check the code below:
ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
AnimatedScale(
duration: const Duration(milliseconds: 400),
scale: _showZoom["$index"] == true
? zoomTargetWidth / zoomOriginalWidth
: 1,
child: Image.network(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
),
if (_showZoom["$index"] == null || _showZoom["$index"] == false)
Container(
color: Colors.black.withAlpha(100),
height: zoomOriginalHeight,
width: zoomOriginalWidth,
),
],
),
),
Check out the screenshot and the live demo on DartPad:
All source
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 createState() => _MyHomePageState();
}
class _MyHomePageState extends State {
final double zoomTargetHeight = 320;
final double zoomTargetWidth = 500;
final double zoomOriginalHeight = 225;
final double zoomOriginalWidth = 400;
double _zoomHeight = 225;
double _zoomWidth = 400;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Image.network("https://source.unsplash.com/random/1600x900?cars"),
Container(
color: Colors.black87,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 12,
),
const Text(
"List of items",
style: TextStyle(color: Colors.white),
),
const SizedBox(
height: 12,
),
SizedBox(
height: 235,
child: ListView.separated(
clipBehavior: Clip.none,
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return buildCard(index);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 12,
);
},
itemCount: 10,
),
),
const SizedBox(
height: 200,
),
],
),
),
),
],
),
),
);
}
Map _showZoom = {};
Widget buildCard(int index) {
Stack stack = Stack(
clipBehavior: Clip.none,
children: [
MouseRegion(
onEnter: (event) {
setState(() {
_showZoom["$index"] = true;
});
},
onExit: (event) {
setState(() {
_showZoom["$index"] = false;
});
},
child: ClipRRect(
borderRadius: BorderRadius.circular(20),
child: Stack(
children: [
AnimatedScale(
duration: const Duration(milliseconds: 400),
scale: _showZoom["$index"] == true
? zoomTargetWidth / zoomOriginalWidth
: 1,
child: Image.network(
"https://source.unsplash.com/random/400x225?sig=$index&cars"),
),
if (_showZoom["$index"] == null || _showZoom["$index"] == false)
Container(
color: Colors.black.withAlpha(100),
height: zoomOriginalHeight,
width: zoomOriginalWidth,
),
],
),
),
),
],
);
return stack;
}
}

ListView goes up and down when i scroll it - flutter

I made a listview on flutter but it goes up and down when I scroll it
things I already tried:
Changing the expanded to a container with a limited height
add the shrinkwrap parameter
https://drive.google.com/file/d/1OwFkEd-zqk5z5wF1eBUsjlpSWmbql3vZ/view?usp=sharing
// ignore_for_file: library_private_types_in_public_api
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
final List<String> exercises;
const HomePage({Key? key, required this.exercises}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
const Text(
'Fisioterapia rj',
style: TextStyle(
fontSize: 42
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 20, bottom: 20, right: 30, left: 30),
child: ListView.builder(
shrinkWrap: false,
itemBuilder: (BuildContext context, int index) {
return Container(
color: Colors.black,
child: ListTile(
title: Text(
widget.exercises[index],
style: const TextStyle(
color: Colors.white,
),
),
),
);
},
itemCount: widget.exercises.length,
),
),
),
],
),
),
);
}
}
To change the axis of scroll use
scrollDirection: Axis.horizontal,
Edit
To keep the background without scrolling use the layout as below
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
height:MediaQuery.of(context).size.height,
width:MediaQuery.of(context).size.width,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage("https://dummyimage.com/600x400/000/fff"),
fit:BoxFit.cover
)
),
child: ListView.builder(
itemCount: 40,
itemBuilder: (context, index){
return Container(
child: Text("This item has an index of $index", style:TextStyle(color:Colors.red)),
);
}
),
);
}
}
You do not show code, but I guess, You use kind a scrollview. You can try add parameter: physics = NeverScrollableScrollPhysics(), to ListView widget.
The ListView.builder widget has a default padding due to which it scrolls. You need to set the default padding to zero to disable such scrolling effect as follows:
padding: EdgeInsets.zero
So the listview builder code becomes as show below:
ListView.builder(
padding: EdgeInsets.zero,
shrinkWrap: false,
itemBuilder: (BuildContext context, int index) {
return Container(
color: Colors.black,
child: ListTile(
title: Text(
widget.exercises[index],
style: const TextStyle(
color: Colors.white,
),
),
),
);
},
itemCount: widget.exercises.length,
),

Issue when I try creating Sliver app bar and pageview in the same widget

I am facing issues when it comes to logic while I am working with my app
I want a sliver appBar with and a page view in the same widget when i
do that and assign a custom scroll view for each page of my pageviews I get problems but if I declared a sliver app bar on each page of the pages it works fine and at the same time I should not have a nested scroll view in my pageview widget now I don't think that I should write an app bar for each one of them when I could just write it my page view widget
any thoughts
this is my code
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
top: true,
bottom: false,
child:
NestedScrollView(
floatHeaderSlivers: true,
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
context),
sliver:
SliverAppBar(
// toolbarHeight: 50,
backgroundColor: Color.fromRGBO(255, 255, 255, 1),
title: const Text(
'Partnerna',
style: TextStyle(
fontSize: 21,
fontWeight: FontWeight.bold,
fontStyle: FontStyle.normal,
color: linerColorUp),
),
actions: [
Padding(
padding: const EdgeInsets.symmetric(
vertical: 0, horizontal: 10),
child: Container(
alignment: Alignment.centerRight,
// color: Colors.amber,
// width: double.infinity,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: const [
CircelCntainerBackgroundWidget(
backGroundColor: buttonbackgroundcolor,
child: Padding(
padding: EdgeInsets.all(3),
child: FaIcon(
FontAwesomeIcons.squarePlus,
size: 18,
),
)),
SizedBox(
width: 20,
),
CircelCntainerBackgroundWidget(
backGroundColor: buttonbackgroundcolor,
child: Icon(
Icons.notification_add_rounded,
size: 21,
)),
SizedBox(
width: 20,
),
// SizedBox(width: 10,),
CircleAvatar(
radius: 14,
backgroundImage: NetworkImage(
"https://th.bing.com/th/id/OIP.2tWiaVWFJjvC1HhJQuTtCwHaHt?w=173&h=181&c=7&r=0&o=5&pid=1.7"),
),
],
),
),
)
],
// expandedHeight: 200,
floating: true,
pinned: false,
snap: true,
forceElevated: innerBoxIsScrolled,
elevation: 0,
),
)];
},
body:
PageView(
children: [
HomeScreen(),
ConnectScreen(),
ConnectRequestScreen(),
MessagScrenn(),
SettingScreen(),
],
physics: const NeverScrollableScrollPhysics(),
controller: pageController,
onPageChanged: onPageChange,
),
),),
try to make a custom Scaffold same as your code, to wrap each of the PageView children.
class MyHomePage extends StatefulWidget {
const MyHomePage({
Key? key,
}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: PageView(
children: [
Page1(),
Page2(),
Page3(),
]
),
);
}
}
class Page1 extends StatelessWidget{
#override
Widget build(BuildContext context) {
return CustomScaffold(
body: (...)
);
}
}
class Page2 extends StatelessWidget{
#override
Widget build(BuildContext context) {
return CustomScaffold(
body: (...)
);
}
}
class Page3 extends StatelessWidget{
#override
Widget build(BuildContext context) {
return CustomScaffold(
body: (...)
);
}
}
class CustomScaffold extends StatefulWidget {
final Widget body;
const CustomScaffold({ Key? key, required this.body}) : super(key: key);
#override
_CustomScaffoldState createState() => _CustomScaffoldState();
}
class _CustomScaffoldState extends State<CustomScaffold> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled){
(...)
},
body: widget.body,
),
);
}
}

Create additional cards on button press

I have a Stateful widget class with a card, the card has a dropdown and a text field. There is a Floatingactionbutton, I want to create an additional card when ever the floatingactionbutton is pressed. I guess I am supposed to create a list of this widget, but I am not too sure how to go about it.
Here is the code with the cards.
class CustomerCurrentSuppliers extends StatefulWidget {
const CustomerCurrentSuppliers({Key key}) : super(key: key);
#override
_CustomerCurrentSuppliersState createState() => _CustomerCurrentSuppliersState();
}
class _CustomerCurrentSuppliersState extends State<CustomerCurrentSuppliers> {
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blue,
child: Icon(Icons.add),
onPressed: () {
//This is where the code to create additional cards come in ------>
},
),
body: Padding(
padding: const EdgeInsets.only(top: 38.0, right: 10, left: 10),
child: Column(
children: [
Container(
height: 170,
child: Card(
child:
Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: DropdownButtonHideUnderline(
child: FormBuilderDropdown(
name: 'dropdown',
hint: Text("Year"),
isExpanded: true,
items: [
"2018",
"2019",
"2020",
"2021",
].map((option) {
return DropdownMenuItem(
child: Text("$option"),
value: option,
);
}).toList(),
),
),
),
SizedBox(height: 20,),
Padding(
padding: const EdgeInsets.all(8.0),
child: FormBuilderTextField(
name: 'Region',
decoration: InputDecoration(
labelText: "Amount",
border: OutlineInputBorder()),
validator: FormBuilderValidators.compose([
FormBuilderValidators.required(context),
]),
),
),
],
),
elevation: 8,
),
),
],
),
),
);
}
}
You didn't provide the full code but I understand the logic you want.
Here is the code.
import 'package:flutter/material.dart';
class CustomerCurrentSuppliers extends StatefulWidget {
const CustomerCurrentSuppliers({Key key}) : super(key: key);
#override
_CustomerCurrentSuppliersState createState() => _CustomerCurrentSuppliersState();
}
class _CustomerCurrentSuppliersState extends State<CustomerCurrentSuppliers> {
int counter=1;
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blue,
child: Icon(Icons.add),
onPressed: () {
setState(() { //setState is used to update the UI
counter++;
});
},
),
body: Padding(
padding: const EdgeInsets.only(top: 38.0, right: 20, left: 20),
child: ListView.builder(
itemCount: counter, //updating counter will update the UI with new card
itemBuilder: (context,index){
return Card(
child: Center(
child: Text(
"This is card ${index+1}"
),
),
);
}),
),
);
}
}
You can create List and increment the List when fab pressed.
class CustomerCurrentSuppliers extends StatefulWidget {
#override
_CustomerCurrentSuppliersState createState() =>
_CustomerCurrentSuppliersState();
}
class _CustomerCurrentSuppliersState extends State<CustomerCurrentSuppliers> {
int cardCount = 1;
List<int> cardList = [1];
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.blue,
child: Icon(Icons.add),
onPressed: () {
cardCount += 1;
cardList.add(cardCount);
setState(() {});
},
),
body: Padding(
padding: const EdgeInsets.only(top: 38.0, right: 10, left: 10),
child: ListView.builder(
itemCount: cardList.length,
itemBuilder: (content, index) {
return Container(
height: 170,
child: Card(
child: Column(
children: [
Text('FormBuilderDropdown'),
SizedBox(
height: 20,
),
Text('Region')
],
),
elevation: 8,
),
);
})),
);
}
}
Note: You have to handle errors/add more logics when pressing the button otherwise list will increment every time user press the button.

GridView and CachedNetworkImage - Reloading image on scrolling

I'm getting a list of items from API and each item contains an image and these items should be displayed in GridView. I'm using GridView.count for building and CachedNetworkImage for loading images from the network. But when I'm scrolling bottom or top, all images are reloading again giving the experience of lagging.
Image is actually a child of ListItem which is a Stack widget and it should be "background" of ListItem.
Did anyone encounter the same problem and found a solution? I'm using BLOC.
class PlayersPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return buildPlayersPage(context);
}
BlocConsumer buildPlayersPage(BuildContext context) {
return BlocConsumer(
cubit: BlocProvider.of<PlayersBloc>(context),
listener: (context, state) {
if (state is PlayersError) {
return DisplayEmptyState();
}
},
builder: _mapStateToPage,
);
}
Widget _mapStateToPage(context, state) {
if (state is PlayersInitial) {
return DisplayLoading();
} else if (state is PlayersLoading) {
return DisplayLoading();
} else if (state is PlayersLoaded) {
return DisplayPlayersGridView(state.players);
} else {
return DisplayEmptyState();
}
}
}
class DisplayPlayersGridView extends StatelessWidget {
final List<Player> players;
DisplayPlayersGridView(this.players);
#override
Widget build(BuildContext context) {
return GridView.count(
crossAxisCount: 2,
crossAxisSpacing: 8.0,
childAspectRatio: 0.9,
mainAxisSpacing: 8.0,
padding: EdgeInsets.all(8.0),
children: players.map((player) => TeamListItem(player)).toList());
}
}
class TeamListItem extends StatelessWidget {
final Player player;
TeamListItem(this.player);
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Container(
child: Stack(
alignment: Alignment.topLeft,
children: [
PlayerImage(player.playerPictureOne),
NumberContainer(player.squadNumber),
SponsorRectangle(player.sponsoredBy),
PlayersDetailsContainer(player.playerName, player.position),
Positioned(
right: 16.0,
bottom: 16.0,
child: Image.asset(
ViewUtils.getCountryFlag(player.country.toLowerCase()),
package: 'country_icons',
width: 15,
height: 10,
fit: BoxFit.cover,
),
)
],
),
),
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PlayerDetailsPage(
player: player,
),
)),
);
}
}
class PlayersDetailsContainer extends StatelessWidget {
final String playerName;
final String position;
PlayersDetailsContainer(this.playerName, this.position);
#override
Widget build(BuildContext context) {
return Positioned(
left: 16.0,
bottom: 16.0,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
playerName,
style: TextStyle(fontSize: 13.0, color: Colors.white),
),
SizedBox(height: 4.0),
Text(position.toUpperCase(),
style: TextStyle(fontSize: 10.0, color: Colors.white))
],
),
);
}
}
class SponsorRectangle extends StatelessWidget {
final String sponsoredBy;
SponsorRectangle(this.sponsoredBy);
#override
Widget build(BuildContext context) {
return Positioned(
left: 30.0,
child: Container(
width: 100.0,
height: 15.0,
color: ColorsUtils.ACCENT_COLOR,
alignment: Alignment.center,
child: Text(
sponsoredBy,
style: TextStyle(fontSize: 8.0, color: Colors.white),
),
),
);
}
}
class NumberContainer extends StatelessWidget {
final String playerNumber;
NumberContainer(this.playerNumber);
#override
Widget build(BuildContext context) {
return Container(
width: 30.0,
height: 30.0,
alignment: Alignment.center,
color: Colors.black,
child: Text(
playerNumber,
style: TextStyle(fontSize: 15.0, color: Colors.white),
),
);
}
}
class PlayerImage extends StatelessWidget {
final String imageUrl;
PlayerImage(this.imageUrl);
#override
Widget build(BuildContext context) {
return CachedNetworkImage(
imageUrl: imageUrl,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
imageBuilder: (context, imageProvider) => Container(
decoration: BoxDecoration(
image: DecorationImage(image: imageProvider, fit: BoxFit.cover),
),
),
);
}
}