TabBarView inside Sliver with StickyHeader - flutter

I have made this layout so far using CustomScrollView and Sticky Header
https://imgur.com/a/Xo4AfAM
What I want to achieve is that the content below the tabs should not scroll unless there is extra content available. Also, after scrolling, the content should not go behind the sticky header.
My Code so far.
Scaffold(
backgroundColor: Colors.white,
extendBodyBehindAppBar: true,
appBar: AppBar(
toolbarHeight: getHeight() * (1 / 11),
),
body: Padding(
padding: getPaddings(),
child: DefaultTabController(
length: 3,
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
height: getHeight() * (3 / 11),
color: Colors.blue,
),
),
SliverStickyHeader(
header: Column(
children: [
Container(
height: getHeight() * (1 / 11),
width: double.infinity,
color: kPrimaryColor,
child: Center(
child: Text(
"TEXT",
style: TextStyle(
fontSize: 32,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
Container(
height: getHeight() * (1 / 11),
color: kPrimaryColor,
child: TabBar(
tabs: [
Tab(
child: Text(
'TITLE1',
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
'TITLE2',
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
'TITLE3',
style: TextStyle(color: Colors.black),
),
),
],
),
),
],
),
sliver: SliverFillRemaining(
child: TabBarView(
children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(50),
vertical: getProportionateScreenHeight(20)),
child: Column(
children: [
RoundedPicture(),
FittedBox(
child: Text("Hello World",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 40)),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20),
text: 'Info1: ',
children: [
TextSpan(
text: "123",
style: TextStyle(
color: kSecondaryColor,
),
),
]),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
RichText(
text: TextSpan(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20),
text: 'Info2: ',
children: [
TextSpan(
text: "abcd",
style: TextStyle(
color: kSecondaryColor,
),
),
]),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
RichText(
text: TextSpan(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20),
text: 'Info3: ',
children: [
TextSpan(
text: "xyz",
style: TextStyle(
color: kSecondaryColor,
),
),
]),
),
],
),
],
),
),
Center(
child: Text("TITLE2"),
),
Center(
child: Text("TITLE3"),
),
],
),
),
),
],
),
),
),
To achieve the required layout, I tried using TabBarView inside different slivers i.e SliverList and SliverToBoxAdapter but they all resulted in an error because TabBarView doesn't have a predefined height.

Here is my implementation.
Because there are no method related to size, I just set a value myself.
Stack
DefaultTabController
NestedScrollView
SliverAppBar
SliverPersistentHeader
SliverPersistentHeader
TabBarView
Container // For back button
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
super.initState();
_tabController = TabController(initialIndex: 0, length: 3, vsync: this);
}
double getHeight() {
return 800;
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
extendBodyBehindAppBar: true,
body: SafeArea(
child: Stack(
children: [
DefaultTabController(
length: 3,
child: NestedScrollView(
headerSliverBuilder: (context, value) {
return [
SliverAppBar(
expandedHeight: 200.0,
flexibleSpace: FlexibleSpaceBar(),
),
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 90,
maxHeight: 90,
child: Container(
height: getHeight() * (1 / 11),
width: double.infinity,
color: Colors.green[200],
child: Center(
child: Text(
"TEXT",
style: TextStyle(
fontSize: 32,
color: Colors.white,
fontWeight: FontWeight.bold,
),
),
),
),
),
),
SliverPersistentHeader(
pinned: true,
delegate: _SliverAppBarDelegate(
minHeight: 90,
maxHeight: 90,
child: Container(
color: Colors.green[200],
child: TabBar(
controller: _tabController,
tabs: [
Tab(
child: Text(
'TITLE1',
style: TextStyle(
color: Colors.black,
),
),
),
Tab(
child: Text(
'TITLE2',
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
'TITLE3',
style: TextStyle(color: Colors.black),
),
),
],
),
),
),
),
];
},
body: TabBarView(
controller: _tabController,
children: [
SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(bottom: 600),
child: Column(
children: [
// RoundedPicture(),
Icon(
Icons.favorite,
color: Colors.pink,
size: 150.0,
semanticLabel:
'Text to announce in accessibility modes',
),
FittedBox(
child: Text("Hello World",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 40)),
),
SizedBox(
height: 20,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20),
text: 'Info1: ',
children: [
TextSpan(
text: "123",
style: TextStyle(),
),
]),
),
SizedBox(
height: 20,
),
RichText(
text: TextSpan(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20),
text: 'Info2: ',
children: [
TextSpan(
text: "abcd",
style: TextStyle(),
),
]),
),
SizedBox(
height: 20,
),
RichText(
text: TextSpan(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 20),
text: 'Info3: ',
children: [
TextSpan(
text: "xyz",
style: TextStyle(),
),
]),
),
],
),
],
),
),
),
SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(bottom: 600),
child: Column(
children: [
Container(
padding: EdgeInsets.only(bottom: 600),
child: Center(
child: Text("TITLE2"),
),
),
],
),
),
),
SingleChildScrollView(
child: Container(
padding: EdgeInsets.only(bottom: 600),
child: Column(
children: [
Container(
padding: EdgeInsets.only(bottom: 600),
child: Center(
child: Text("TITLE3"),
),
),
],
),
),
),
],
),
),
),
Container(
height: 90,
padding: EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () {},
child: Icon(Icons.arrow_back),
),
),
],
),
),
);
}
}
class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
_SliverAppBarDelegate({
#required this.minHeight,
#required this.maxHeight,
#required this.child,
});
final double minHeight;
final double maxHeight;
final Widget child;
#override
double get minExtent => minHeight;
#override
double get maxExtent => math.max(maxHeight, minHeight);
#override
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return SizedBox.expand(child: child);
}
#override
bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
return maxHeight != oldDelegate.maxHeight ||
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}

After finding no possible solution, I decided to implement my own tab bar view instead of using the default one. The solution isn't as fancy since the transition of tabs is done by changing the current page number and rebuilding the widget but solves the issue. I used a gesture detector for allowing users to swipe the page.
GestureDetector(
onHorizontalDragEnd: (dragDetails) {
if (dragDetails.primaryVelocity != 0) {
final int val = dragDetails.primaryVelocity.sign.toInt();
if (currentPage - val >= 0 &&
currentPage - val < tabController.length)
tabController.animateTo(currentPage - val);
}
},
child: CustomScrollView(
shrinkWrap: true,
controller: scrollController,
slivers: [
SliverToBoxAdapter(
child: LogoContainer(),
),
SliverStickyHeader(
header: Column(
children: [
NameContainer(text: 'TEXT'),
Container(
height: 60,
color: kSecondaryColor,
child: TabBar(
controller: tabController,
tabs: [
Tab(
child: Text(
'TITLE1',
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
'TITLE2',
style: TextStyle(color: Colors.black),
),
),
Tab(
child: Text(
'TITLE3',
style: TextStyle(color: Colors.black),
),
),
],
),
),
],
),
sliver: SliverToBoxAdapter(
child: ConstrainedBox(
constraints:
BoxConstraints(minHeight: getHeight() * (6 / 11)),
child: [
Column(
children: [
RoundedPicture(),
FittedBox(
child: Text(
'HELLO WORLD',
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black,
fontSize: 40),
),
),
SizedBox(
height: getProportionateScreenHeight(20),
),
Column(
children: [
ProfileInfoText(
title: 'INFO1',
text: 'abcd',
),
SizedBox(
height: getProportionateScreenHeight(20),
),
ProfileInfoText(
title: 'INFO2',
text: '123',
),
SizedBox(
height: getProportionateScreenHeight(20),
),
ProfileInfoText(
title: 'INFO3',
text: 'xyz',
),
],
),
],
),
Center(
child: Text("TITLE2"),
),
Center(
child: Text("TITLE3"),
),
].elementAt(currentPage),
),
),
),
],
),
),
I also used scroll controller to animate the list back to top when changing the tabs to give it a smooth look.
#override
void initState() {
super.initState();
tabController = TabController(length: 3, vsync: this)
..addListener(() async {
await scrollController.animateTo(
0,
duration: Duration(seconds: 1),
curve: Curves.ease,
);
setState(() {
currentPage = tabController.index;
});
});
}

Related

How to make Container height dynamic to fit ListView but to certain max height Flutter

I am trying to show ListView in a custom dialog window. What I want to make dialog box height dynamic according to ListView content but to certain max height. If the ListView content reaches specific height it should me scrollable.
This is my code:
class PeekTableDialog extends StatefulWidget {
Order order;
PeekTableDialog({required this.order});
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return PeekTableDialogState();
}
}
class PeekTableDialogState extends State<PeekTableDialog> {
final ScrollController controller = ScrollController();
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
}
Widget getExtras(Food fooditem) {
List<String> extras = [];
for (var extra in fooditem.extras) {
if (fooditem.extras.last == extra) {
extras.add(extra.name);
} else {
extras.add(extra.name + ', ');
}
}
return Wrap(
runSpacing: 2,
spacing: 2,
children: List.generate(
extras.length,
(index) {
return Text(
extras[index].toString(),
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.normal,
fontStyle: FontStyle.italic,
),
);
},
),
);
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return SizedBox(
width: MediaQuery.of(context).size.width * 0.50,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: double.infinity,
color: Colors.grey[400],
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 10),
alignment: Alignment.center,
child: Row(
children: [
Expanded(
child: Container(
alignment: Alignment.center,
child: Text(
widget.order.table!.name,
style: AppTextStyles().style2,
),
),
),
IconButton(
onPressed: () {
Navigator.of(context).pop();
},
padding: EdgeInsets.zero,
icon: Icon(
Icons.close,
color: Colors.white,
size: 35,
),
),
],
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
alignment: Alignment.center,
child: Text(
'\$' + widget.order.total,
style: TextStyle(
color: Colors.grey[800],
fontSize: 35,
fontWeight: FontWeight.w400,
),
),
),
SizedBox(
height: 15,
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Expanded(
child: Text(
'Qty',
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
),
const SizedBox(
width: 10,
),
Expanded(
flex: 2,
child: Text(
'Item',
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Container(
child: Text(
'Price',
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Container(
child: Text(
'Disc.',
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.w700,
),
),
),
),
],
),
const Divider(
color: Colors.grey,
height: 1.5,
),
const SizedBox(
height: 10,
),
Container(
padding: EdgeInsets.only(bottom: 30),
child: Scrollbar(
isAlwaysShown: true,
controller: controller,
thickness: 12,
showTrackOnHover: true,
child: ListView.separated(
itemCount: widget.order.cartItems.length,
controller: controller,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemBuilder: (context, index) {
return Container(
child: Row(
children: [
Expanded(
child: Container(
alignment: Alignment.centerLeft,
child: Text(
widget.order.cartItems[index].cartCount
.toString(),
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
),
),
const SizedBox(
width: 10,
),
Expanded(
flex: 2,
child: Container(
alignment: Alignment.centerLeft,
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
widget.order.cartItems[index].name,
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
const SizedBox(
height: 5,
),
getExtras(widget.order.cartItems[index]),
],
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Container(
alignment: Alignment.centerLeft,
child: Text(
'\$' +
widget.order.cartItems[index].totalPrice
.toStringAsFixed(2),
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
),
),
const SizedBox(
width: 10,
),
Expanded(
child: Container(
alignment: Alignment.centerLeft,
child: Text(
'\$' +
widget
.order.cartItems[index].newDiscPrice
.toStringAsFixed(2),
style: TextStyle(
color: Colors.grey[700],
fontSize: 14,
fontWeight: FontWeight.normal,
),
),
),
),
],
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(height: 3);
},
),
),
),
],
),
),
],
),
);
}
}
Anyone help me please with this small issue.
Thanks in advance.
Well, It's pretty easy. All you have to do is to create a class like this :
class ExpandableText extends StatefulWidget {
ExpandableText(this.text, this.isLongText, {Key? key}) : super(key: key);
final String text;
bool isExpanded = false;
final bool isLongText;
#override
_ExpandableTextState createState() => _ExpandableTextState();
}
class _ExpandableTextState extends State<ExpandableText>
with TickerProviderStateMixin<ExpandableText> {
#override
void initState() {
if (widget.isLongText) {
setState(() {
widget.isExpanded = false;
});
} else {
widget.isExpanded = true;
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
AnimatedSize(
vsync: this,
duration: const Duration(milliseconds: 500),
child: ConstrainedBox(
constraints: widget.isExpanded
? const BoxConstraints(maxHeight: 250.0)
: const BoxConstraints(
maxHeight: 60.0,
),
child: SingleChildScrollView(
child: Text(
widget.text,
overflow: TextOverflow.fade,
),
),
),
),
widget.isExpanded
? ConstrainedBox(constraints: const BoxConstraints())
: TextButton(
style: const ButtonStyle(alignment: Alignment.topRight),
child: const Text(
'Expand..'
),
onPressed: () => setState(() => widget.isExpanded = true),
),
],
);
}
}
Just play with the maxHeight according to your needs. Call this class like this (inside your dialog window) :
ExpandableText(
dataToBeShown,
dataToBeShown.length > 250 ? true : false,
),

How to align bottom container inside listview?

I wanted to aling a button to the bottom center of the listview.
Scaffold(
backgroundColor: Colors.white,
appBar: buildAppBar(context, ''),
body: ListView(
physics: ClampingScrollPhysics(),
children: [
Column(
children: [
Text(
'check up',
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 12),
Text(
'SachsenwaldStr. 3. 12157 Berlin',
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
],
),
Spacer(),
buildNextButton(context),
],
),
I tried using Align, but it didn't work, and Spacer() didn't too:
Align(
alignment: Alignment.bottomCenter,
child: buildNextButton(context),
),
is there any way to align buildNextButton to the bottom?
return Scaffold(
body: Stack(
children: [
Positioned(
bottom: 0,
width: MediaQuery.of(context).size.width,
child: Center(
child: MaterialButton(
child: Text("My button"),
onPressed: () {},
color: Colors.red,
),
),
),
ListView(
children: [
Text(
'check up',
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 12),
Text(
'SachsenwaldStr. 3. 12157 Berlin',
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
],
)
],
));
You can use Scaffold Properties to make a button centre at the bottom. Hope it would be helpful for you,Thanks
import 'package:flutter/material.dart';
class BottomButton extends StatefulWidget {
const BottomButton({Key? key}) : super(key: key);
#override
_BottomButtonState createState() => _BottomButtonState();
}
class _BottomButtonState extends State<BottomButton> {
#override
Widget build(BuildContext context) {
return Scaffold(
///you can make the centre button use floating action Button and
provide its location
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.transparent,
child: Container(
width: MediaQuery.of(context).size.width,
color: Colors.green,
child: Text(
"Button")),
onPressed: () {},
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
appBar: AppBar(
title: Text("MyAppBar"),
),
body: ListView(
physics: ClampingScrollPhysics(),
children: [
Column(
children: [
Text(
'check up',
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 12),
Text(
'SachsenwaldStr. 3. 12157 Berlin',
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
],
),
],
),
///bottom sheet place button at bottom without using space
bottomSheet: Container(
width: MediaQuery.of(context).size.width,
color: Colors.green,
child: TextButton(onPressed: () {}, child: Text("Button"))),
);
}
}
You can wrap your Align widget with Expanded and in Align widget use alignment: FractionalOffset.bottomCenter .
Please find below link to get more clear idea - Button at bottom
I suggest to wrap ListView and builtNextButton with Stack Widget.
Because when ListView children is bigger than screen height, button can not be located bottom.
import 'package:flutter/material.dart';
const Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
Widget buildNextButton(context) {
return Container(height: 40, color: Colors.green);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(
scaffoldBackgroundColor: darkBlue,
),
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.white,
//appBar: buildAppBar(context, ''),
body: Stack(
children: [
ListView(
physics: const ClampingScrollPhysics(),
children: [
Column(
children: [
Text(
'check up',
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 12),
Text(
'SachsenwaldStr. 3. 12157 Berlin',
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
],
),
],
),
Align(
alignment: Alignment.bottomCenter,
child: buildNextButton(context),
),
],
),
),
);
}
}
Now the only way you can use it in a list view is if you are to pas it in a column widget, so the order would become, column -> Expanded -> ListView andoutside the expanded, that is where you now pass the button. Just copy and paste my code here, Hopefully it works for you.
Scaffold(
body: Column(
children: [
Expanded(
child: ListView(
// physics: ClampingScrollPhysics(),
children: [
Column(
children: [
Text(
'check up',
style: TextStyle(
fontSize: 35,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
SizedBox(height: 12),
Text(
'SachsenwaldStr. 3. 12157 Berlin',
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
],
),
// buildNextButton(context),
],
),
),
Container(
child: Center(
child: buildNextButton()
),
)
],
),
)
and then the buildNextButton code is
buildNextButton() {
return ElevatedButton(
style: ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20))
,
onPressed: () {},
child: const Text('Enabled'),
);
}
the moment you render a listview as aparent widget, automatically it renders all items in alist, one after the other.
anyquestions, am available to help you out
Good luck bro

Flutter noob needs some help: screen dont show the result

I try to use the info class as a sample for multiple classes but my problem is when i run the app i only can see a white background. Sorry for the long code I am very new at programming and try to be better soon :)
class kaminfeuerinfo extends StatefulWidget {
#override
_kaminfeuerinfoState createState() => _kaminfeuerinfoState();
}
class _kaminfeuerinfoState extends State<kaminfeuerinfo> {
List <Info> inhalt = [
Info(name: 'hallo', beschreibung: '1', preis: '2', kilo: 'f', details: 'f,', artikelnummer: 'd',zutaten: 'f',
verkehrsbezeichnung: 'z', inverkehrbringer: 'h', kj: 'h', kcal: 'h',fett: 'h',
saeure: 'g', kohlenhydrate: 'h',zucker: 'k', eiweiss: 't', salz: 't')
];
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children:
inhalt.map((inhalt) => info (inhalt: inhalt)).toList(),
),
),
);
}
}
class Info {
String name;
String beschreibung;
String preis;
String kilo;
String details;
String artikelnummer;
String zutaten;
String verkehrsbezeichnung;
String inverkehrbringer;
String kj;
String kcal;
String fett;
String saeure;
String kohlenhydrate;
String zucker;
String eiweiss;
String salz;
Info({this.name,this.beschreibung, this.preis, this.kilo, this.details, this.artikelnummer, this.zutaten, this.verkehrsbezeichnung,
this.inverkehrbringer, this.kj, this.kcal, this.fett, this.saeure, this.kohlenhydrate, this.zucker, this.eiweiss, this.salz,});
}
this isn't all of the code because the code takes more than 500 rows, but i hope it is enough for you too help me with my problem:)
class info extends StatelessWidget {
final Info inhalt;
info ({this.inhalt});
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: <Widget>[
IconButton(
onPressed: () {
showSearch(context: context, delegate: suchen());
},
icon: Icon(Icons.search))
],
title: Image.asset(
"assets/images/logo_465x320.png",
width: 150,
),
centerTitle: true,
backgroundColor: Colors.brown,
),
body: SingleChildScrollView(
child: Container(
alignment: Alignment.center,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
SizedBox(
height: 10.0,
),
Container(
alignment: Alignment.center,
child: Text(
inhalt.name,
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
SizedBox(
height: 7.0,
),
Container(
alignment: Alignment.center,
margin: EdgeInsets.only(left: 20, right: 20),
child: AutoSizeText(
inhalt.beschreibung,
textAlign: TextAlign.center,
maxLines: 15,
style: TextStyle(fontSize: 10),
),
width: 130,
),
SizedBox(
height: 7.0,
),
Container(
child: Carousel(
images: [
Image.asset(
"assets/images/kenia.jpg",
),
Image.asset(
"assets/images/tee2.jpg",
),
Image.asset(
"assets/images/tee.jpg",
),
],
autoplay: false,
dotBgColor: Colors.transparent,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomRight,
dotColor: Colors.white38,
dotIncreasedColor: Colors.white60,
dotIncreaseSize: 3,
dotSize: 3,
dotSpacing: 12,
),
height: 200.0,
),
SizedBox(
height: 10.0,
),
Container(
child: SizedBox(
width: 200.0,
height: 250.0,
child: DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
backgroundColor: Colors.white,
automaticallyImplyLeading: false,
title: Column(
children: [
Container(
child: Text(
inhalt.preis,
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.black),
textAlign: TextAlign.center,
),
),
Container(
child: Text(
inhalt.kilo,
style: TextStyle(
fontSize: 10.0, color: Colors.black),
textAlign: TextAlign.center,
),
),
Container(
alignment: Alignment.bottomRight,
child: Text(
"inkl. 7% MwSt.",
style: TextStyle(
fontSize: 10.0, color: Colors.black),
textAlign: TextAlign.right,
),
)
],
),
centerTitle: true,
bottom: PreferredSize(
preferredSize: Size.fromHeight(50),
child: TabBar(
tabs: [
Tab(
text: "Details",
),
Tab(
text: "Informationen",
),
],
isScrollable: true,
unselectedLabelColor: Colors.black,
indicatorColor: Colors.black,
labelColor: Colors.black,
),
)),
body: TabBarView(
children: [
Container(
padding: EdgeInsets.all(20),
child: Text(
inhalt.details,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 15,
),
),
),
],
),
),
)),
color: Colors.white,
),
],
),
),
),
);
}
}
To see the list on the screen as a list you will have to use ListView.builder here on your State class:
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children:
inhalt.map((inhalt) => info (inhalt: inhalt)).toList(),
),
),
);
}
}
Here you have detailed documentation I advise you to get familiar with:
https://api.flutter.dev/flutter/widgets/ListView-class.html

Flutter how give a gap between containers in SliverChildBuilderDelegate

I am using SliverAppBar in my app which is working fine but problem is in list of container its not increasing gap between list
[
My code
import 'package:flutter/material.dart';
class ClaimsScreen extends StatefulWidget {
#override
_ClaimsScreenState createState() => _ClaimsScreenState();
}
class _ClaimsScreenState extends State<ClaimsScreen> {
final List _claims = [
{
'av': '27,000',
'cv': '25,000',
'cqno': '3442121',
'status': 'CLAIM PAYMENT PRCESSED',
'cno': '00651211',
},
{
'av': '29,000',
'cv': '25,000',
'cqno': '3442121',
'status': 'CLAIM PAYMENT PRCESSED',
'cno': '00651211',
},
];
#override
Widget build(BuildContext context) {
double statusBarHeight = MediaQuery.of(context).padding.top;
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Expanded(
child: Container(
child: new CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
new SliverAppBar(
backgroundColor: Colors.white,
expandedHeight: statusBarHeight * 5,
flexibleSpace: new FlexibleSpaceBar(
title: const Text(
'Claims',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 20,
color: Color(0xff00AEF0),
fontWeight: FontWeight.bold),
),
),
),
new SliverPadding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
sliver: new SliverFixedExtentList(
itemExtent: 150.0,
delegate: new SliverChildBuilderDelegate(
(builder, index) => BenefitList(index),
childCount: _claims.length),
)),
],
),
),
);
}
Widget BenefitList(int index) {
double statusBarHeight = MediaQuery.of(context).padding.top;
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Container(
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 30,
child: Container(
child: Padding(
padding: const EdgeInsets.only(right: 10, left: 10, top: 10),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text(
'Approved Value : ',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(
_claims[index]['av'],
style: TextStyle(
fontWeight: FontWeight.bold, color: Color(0xff00AEF0)),
),
],
),
SizedBox(height: height* 0.005,),
Row(
children: <Widget>[
Text(
'Claim Value : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['cv'],
style: TextStyle(
fontWeight: FontWeight.bold, color: Color(0xff00AEF0)),
),
],
),
SizedBox(height: height* 0.005,),
Row(
children: <Widget>[
Text(
'Claim No : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['cno'],
style: TextStyle(
fontWeight: FontWeight.bold, color: Color(0xff00AEF0)),
),
],
),
Row(
children: <Widget>[
Text(
'Cheque Number : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['cqno'],
style: TextStyle(
fontWeight: FontWeight.bold, color: Color(0xff00AEF0)),
),
],
),
SizedBox(height: height* 0.005,),
Row(
children: <Widget>[
Text(
'Status : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['status'],
style: TextStyle(
fontWeight: FontWeight.bold, color: Color(0xff00AEF0)),
)
],
)
],
),
),
),
),
);
}
}
I try to increase the number if itemExtent but it's just increasing the height of card not increasing the gap. I just need to add some gap between each card so when they increase it will automatically show some gap between them. Also, I try to add margin in Container but its also not working
By default SliverFixedExtentList has no gaps between its items. Consider using SliverList instead. Also FYI the new keyword is optional and does not need to be used.
You can copy paste run full code below
You can use Padding and EdgeInsets.only(top: 30)
return Padding(
padding: EdgeInsets.only(top: 30),
child: Container(
child: Card(
working demo
full code
import 'package:flutter/material.dart';
class ClaimsScreen extends StatefulWidget {
#override
_ClaimsScreenState createState() => _ClaimsScreenState();
}
class _ClaimsScreenState extends State<ClaimsScreen> {
final List _claims = [
{
'av': '27,000',
'cv': '25,000',
'cqno': '3442121',
'status': 'CLAIM PAYMENT PRCESSED',
'cno': '00651211',
},
{
'av': '29,000',
'cv': '25,000',
'cqno': '3442121',
'status': 'CLAIM PAYMENT PRCESSED',
'cno': '00651211',
},
];
#override
Widget build(BuildContext context) {
double statusBarHeight = MediaQuery.of(context).padding.top;
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Expanded(
child: Container(
child: new CustomScrollView(
scrollDirection: Axis.vertical,
slivers: <Widget>[
new SliverAppBar(
backgroundColor: Colors.white,
expandedHeight: statusBarHeight * 5,
flexibleSpace: new FlexibleSpaceBar(
title: const Text(
'Claims',
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 20,
color: Color(0xff00AEF0),
fontWeight: FontWeight.bold),
),
),
),
new SliverPadding(
padding: const EdgeInsets.symmetric(vertical: 20.0),
sliver: new SliverFixedExtentList(
itemExtent: 150.0,
delegate: new SliverChildBuilderDelegate(
(builder, index) => BenefitList(index),
childCount: _claims.length),
)),
],
),
),
);
}
Widget BenefitList(int index) {
double statusBarHeight = MediaQuery.of(context).padding.top;
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return Padding(
padding: EdgeInsets.only(top: 30),
child: Container(
child: Card(
clipBehavior: Clip.antiAlias,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 30,
child: Container(
child: Padding(
padding: const EdgeInsets.only(right: 10, left: 10, top: 10),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Text(
'Approved Value : ',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
Text(
_claims[index]['av'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff00AEF0)),
),
],
),
SizedBox(
height: height * 0.005,
),
Row(
children: <Widget>[
Text(
'Claim Value : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['cv'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff00AEF0)),
),
],
),
SizedBox(
height: height * 0.005,
),
Row(
children: <Widget>[
Text(
'Claim No : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['cno'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff00AEF0)),
),
],
),
Row(
children: <Widget>[
Text(
'Cheque Number : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['cqno'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff00AEF0)),
),
],
),
SizedBox(
height: height * 0.005,
),
Row(
children: <Widget>[
Text(
'Status : ',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_claims[index]['status'],
style: TextStyle(
fontWeight: FontWeight.bold,
color: Color(0xff00AEF0)),
)
],
)
],
),
),
),
),
),
);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ClaimsScreen(),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

Flutter: How to set variable length string inside a row?

I am trying to set a string inside a row, but the length of the string is variable i.e data is fetched from API. Then it is set inside the row, but currently, as the length is greater it shows as A RenderFlex overflowed by 48 pixels on the right.
I am been trying to use expanded/flex/flexible but getting incorrect parent error. (Don't know how to as I am new to flutter)
So, please help in how to solve this problem of renderflex overflow.
Following is my method:
void confirmpayment(double amount, String description) {
final itemsSubmit = <Widget>[
Image.asset(
'images/payments.jpg',
width: MediaQuery.of(context).size.width,
fit: BoxFit.contain,
),
ListTile(
title: AutoSizeText(
'Confirmation',
style: TextStyle(fontSize: 20),
),
subtitle: AutoSizeText(
'Hey Gaurav, please confirm examination as payment once done will be irrevocable.',
style: TextStyle(color: Colors.grey),
),
// onTap: () {},
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
),
Padding(
padding: EdgeInsets.only(top: 10),
child: AutoSizeText(
'Exam:',
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 16,
),
),
),
Spacer(),
CheckboxGroup(
orientation: GroupedButtonsOrientation.VERTICAL,
labelStyle: TextStyle(fontSize: 15),
labels: [
...listexam.map((location) {
return location['name']; //this is where string is set from api data
}).toList()
],
checked: _checked,
),
SizedBox(
width: 20,
),
],
),
Divider(),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
),
Padding(
padding: EdgeInsets.only(top: 1),
child: AutoSizeText(
'Plan',
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 16,
),
),
),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 1),
child: AutoSizeText(
description,
textAlign: TextAlign.right,
textDirection: TextDirection.ltr,
style: TextStyle(
fontSize: 15,
),
),
),
),
SizedBox(
width: 20,
),
]),
SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 20,
),
Padding(
padding: EdgeInsets.only(top: 1),
child: AutoSizeText(
'Amount',
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 16,
),
)),
Expanded(
child: Padding(
padding: EdgeInsets.only(top: 1),
child: AutoSizeText(
'Rs. ' + amount.toString(),
textDirection: TextDirection.ltr,
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 15,
// fontWeight: FontWeight.w500,
),
),
),
),
SizedBox(
width: 20,
),
]),
SizedBox(
height: 40,
),
Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
RaisedButton(
elevation: 1,
// onPressed: _showSheetSubmit,
color: Colors.grey[200],
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(28.0),
side: BorderSide(color: Colors.grey[200])),
onPressed: null,
child: AutoSizeText(
"Cancel",
style: TextStyle(
fontSize: 16,
// fontFamily: 'lato',
letterSpacing: 1,
color: Colors.white,
),
)),
RaisedButton(
elevation: 1,
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(28.0),
side: BorderSide(color: Colors.green)),
onPressed: () {
openCheckout(amount, description);
},
child: AutoSizeText(
"Buy",
style: TextStyle(
fontSize: 16,
// fontFamily: 'lato',
color: Colors.white,
letterSpacing: 1),
)),
]),
SizedBox(
height: MediaQuery.of(context).size.height / 12,
),
];
showModalBottomSheet(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
backgroundColor: Colors.white,
context: context,
builder: (BuildContext _) {
return Container(
// color: Colors.white,
child: Wrap(
children: itemsSubmit,
),
);
},
isScrollControlled: true,
// isDismissible: true
);
}
Following is the mock:
Instead of trying to trim the String data that will go into the Text widget, I would use a LayoutBuilder to get the available space that the Row widget could occupy. Then, I would wrap the Text in a SizedBox to limit the maximum width of the Text widget. Finally, I would set the overflow property of the Text widget, so that it shows an ellipsis when the text is longer than the available space.
Here is a little app I wrote for you to see how to do this. You can run it on DartPad to play around with it.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
LayoutBuilder(
builder: (context, constraints) {
return Row(
children: <Widget>[
SizedBox(
width: constraints.maxWidth,
child: Text(
'This is a very very long text that might overflow the available rendering space',
overflow: TextOverflow.ellipsis,
),
),
],
);
},
),
],
),
),
);
}
}