Flutter noob needs some help: screen dont show the result - flutter

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

Related

I can't use the wrap widget side by side

*Create 20 container widgets side by side using the «wrap» widget
*Leave a 3-pixel space between them horizontally.
*Place the containers in the middle of the screen and type 1-2-3-4-5 in them.
I need to design a container widget in line with the above prompts, but when I ran the code I wrote, I saw that the containers are not side by side? What am I doing wrong?
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main()
{runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home:Scaffold(
appBar: AppBar(
title: Text(
"Containers in wraps",
style: TextStyle(color:Colors.greenAccent.shade400),
),
backgroundColor: Colors.black,
),
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Wrap(
alignment: WrapAlignment.center,
spacing:3.0,
runAlignment: WrapAlignment.center,
runSpacing:3.0,
children: [
Expanded(
child: Container(
color: Colors.grey,
child: Center(
child: Text(
"1",
style: TextStyle(color: Colors.red,fontSize: 20),
),
),
),),
SizedBox(width:10,),
Expanded(
child: Container(
color: Colors.lightGreen,
child: Center(
child: Text(
"2",
style: TextStyle(color: Colors.red,fontSize: 20),
),
),
),),
SizedBox(width:10,),
Expanded(
child: Container(
color: Colors.lightGreen,
child: Center(
child: Text(
"3",
style: TextStyle(color: Colors.red,fontSize: 20),
),
),
),),
SizedBox(width:10,),
Expanded(
child: Container(
color: Colors.lightGreen,
child: Center(
child: Text(
"4",
style: TextStyle(color: Colors.red,fontSize: 20),
),
),
),),
SizedBox(width:10,),
Expanded(
child: Container(
color: Colors.blue,
child: Center(
child: Text(
"5",
style: TextStyle(color: Colors.red,fontSize: 20),
),
),
),),
],
),
),
),
),
);
}
Instead of Expanded use UnconstraindedBox. Following code should help:
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AppBar(
title: Text(
"Containers in wraps",
style: TextStyle(color: Colors.greenAccent.shade400),
),
backgroundColor: Colors.black,
),
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Wrap(
alignment: WrapAlignment.center,
spacing: 3.0,
runAlignment: WrapAlignment.center,
runSpacing: 3.0,
children: [
UnconstrainedBox(
child: Container(
constraints: const BoxConstraints.tightFor(),
color: Colors.grey,
child: const Center(
child: Text(
"1",
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
),
),
const SizedBox(
width: 10,
),
UnconstrainedBox(
child: Container(
color: Colors.lightGreen,
constraints: const BoxConstraints.tightFor(),
child: const Center(
child: Text(
"2",
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
),
),
const SizedBox(
width: 10,
),
UnconstrainedBox(
child: Container(
color: Colors.lightGreen,
constraints: const BoxConstraints.tightFor(),
child: const Center(
child: Text(
"3",
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
),
),
const SizedBox(
width: 10,
),
UnconstrainedBox(
child: Container(
color: Colors.lightGreen,
constraints: const BoxConstraints.tightFor(),
child: const Center(
child: Text(
"4",
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
),
),
const SizedBox(
width: 10,
),
UnconstrainedBox(
child: Container(
color: Colors.blue,
constraints: const BoxConstraints.tightFor(),
child: const Center(
child: Text(
"5",
style: TextStyle(color: Colors.red, fontSize: 20),
),
),
),
),
],
),
),
),
),
);
}

How use flexible widget to divide my screen into 2

I would like to divide my screen into 2 using the Flexible Widget. The first flexible widget I would like to set is 80% as yellow and blue for the remaining 20%. Is there any way of dividing it using the flexible widget as I would like to have the remaining 20% of empty space in blue colour.
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text("BitCoin cryptocurrency ")),
body: SingleChildScrollView(
child: Column(
children: [
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Padding(
padding: EdgeInsets.all(8.0),
child: Text(
"BitCoin cryptocurrency",
style:
TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: valueEditingController,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Bitcoin Value',
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0)))),
),
DropdownButton(
itemHeight: 60,
value: selectLoc,
onChanged: (newValue) {
setState(() {
selectLoc = newValue.toString();
});
},
items: locList.map((selectLoc) {
return DropdownMenuItem(
child: Text(
selectLoc,
),
value: selectLoc,
);
}).toList(),
),
ElevatedButton(
onPressed: _loadWeather, child: const Text("Load Value")),
const SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
FittedBox(
child: Text(
// description,
nu,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
),
FittedBox(
child: Text(
nu2,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
),
FittedBox(
child: Text(
nu3,
style: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 25),
),
),//FittedBox
],
),//Column
),//Padding
],
)),//Cloumn //Centre
],
),//Column
)// SingleChildScrollView
);//Scaffold
}
Sorry for any inconvenience.
You can do it by using the Flexible widget with the flex attribute at flex 8 and flex 2
import 'package:flutter/material.dart';
void main() {
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Fexible widget'),
), //AppBar
body: CustomScrollView(
slivers: [
SliverFillRemaining(
hasScrollBody: false,
child: Column(
children: <Widget>[
Flexible(
flex: 8,
fit: FlexFit.loose,
child: Container(
color: Colors.yellow,
), //Container
), //Flexible
Flexible(
flex: 2,
fit: FlexFit.loose,
child: Container(
color: Colors.blue,
), //Container
) //Flexible
//Row
//Row
], //<Widget>[]
),
),
],
),
), //Scaffold
debugShowCheckedModeBanner: false,
),
); //MaterialApp
}

TabBarView inside Sliver with StickyHeader

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

Where in my code should I put BLoC builder and can I have more of them?

So I am trying to learn BLoC pattern and apply it to my weather app. The thing is the UI is kinda big, there are a lot of Columns and Rows. So I'm confused about where to put BlocBuilder.
Or maybe this whole Container should be returned by one BLoC event? This is basically the main and only screen of the app for now.
class WeatherMainScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: kBackgroundColor,
child: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
margin: EdgeInsets.only(
bottom: 30,
top: 15,
left: 30,
right: 30,
),
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Today 28. apr',
style: TextStyle(
color: kAccentColor,
fontSize: 18,
fontWeight: FontWeight.w400,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
MenuSearchButton(
boxSize: 60,
onPressed: () => print('search pressed'),
content: Icon(
Icons.search,
color: Colors.white,
size: 30,
),
),
MenuSearchButton(
boxSize: 60,
onPressed: () => print('menu pressed'),
content: Icon(
Icons.menu,
color: Colors.white,
size: 30,
),
),
],
),
],
),
Container(
padding: EdgeInsets.symmetric(vertical: 20.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'16',
style: TextStyle(
color: Colors.white,
fontSize: 100,
),
),
Container(
padding: EdgeInsets.only(left: 10.0),
child: Row(
children: <Widget>[
Icon(
Icons.cloud,
color: Colors.white,
size: 25.0,
),
SizedBox(width: 15.0),
Text(
'Raining',
style: TextStyle(
color: Colors.white,
fontSize: 18,
),
),
],
),
),
],
),
),
],
),
),
Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(
bottom: 30,
top: 15,
left: 60,
right: 60,
),
child: Text(
'Put on your coat, and don\'t forget the umbrella.',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
Divider(
color: kAccentColor,
),
Container(
margin: EdgeInsets.only(
bottom: 30,
top: 15,
left: 30,
right: 30,
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
DetailedCard(
header: 'HUMIDITY',
headerColor: kAccentColor,
text: '87%',
textColor: Colors.white,
),
DetailedCard(
header: 'WIND M/S',
headerColor: kAccentColor,
text: '4,1',
textColor: Colors.white,
),
DetailedCard(
header: 'FEELS LIKE',
headerColor: kAccentColor,
text: '18',
textColor: Colors.white,
),
],
),
),
],
),
],
),
),
);
}
}
Just separate your UI based on different possible states. Then use BlocBuilder and check states. Finally render UI for respective state.
You can check this video
You can definitely have multiple BlocBuilder. To make it simpler, let's take a look at this Counter example app.
I put this one wrapping a Column with 2 Text Widgets even though the only one supposed to be changing is the second Text Widget. (Not a good thing)
class CounterPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Center(
child: Column(
children: <Widget>[
Text(
'You have pressed this many',
style: TextStyle(fontSize: 24.0),
),
Text(
'$count',
style: TextStyle(fontSize: 24.0),
),
],
),
);
},
),
);
}
}
In this snippet, I put the BlocBuilder pricisely wrapping the only Widget that is changing on state changes. And if you ask Where in my code should I put BLoC builder? This approach is better because there won't be unnecessary Widget rebuilds happen.
class CounterPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Counter')),
body: Center(
child: Column(
children: <Widget>[
Text(
'You have pressed this many',
style: TextStyle(fontSize: 24.0),
),
BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text(
'$count',
style: TextStyle(fontSize: 24.0),
);
},
),
],
),
),
);
}
}
And for can I have more of them?, absolutely.
class CounterPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return AppBar(title: Text('$count'));
},
),
body: Center(
child: Column(
children: <Widget>[
Text(
'You have pressed this many',
style: TextStyle(fontSize: 24.0),
),
BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text(
'$count',
style: TextStyle(fontSize: 24.0),
);
},
),
],
),
),
);
}
}

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