Side by side components in flutter - flutter

I am trying to make an icon and text in a container side by side by using a row and a column but I haven't been able to get results I want. On the first picture it's my code and on the second it's what I want to achieve. Any help would be app. Also, how do I implement a divider with a different color? Cheers

You are using TextField in your ReusableCard right?
Sure thing you can make it with Row but in this case this is usually done with suffixIcon property:
TextField(
decoration: InputDecoration(
suffixIcon: Icon(Icons.search),
),
Or you can just wrap children widgets that has to be in a row in a, well Row widget. Here is example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
TextStyle _style = TextStyle(color: Colors.yellow[800], fontSize: 30);
Color _color = Colors.yellow[800];
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
backgroundColor: Colors.blue[800],
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
children: [
Icon(Icons.done, color: _color),
SizedBox(width: 15),
Text('Electricity', style: _style),
Spacer(),
Icon(Icons.done, color: _color),
SizedBox(width: 15)
],
),
Divider(color: _color),
Row(
children: [
Icon(Icons.done, color: _color),
SizedBox(width: 15),
Text('Internet', style: _style),
Spacer(),
Icon(Icons.done, color: _color),
SizedBox(width: 15)
],
),
Divider(),
],
)),
);
}
}

Spacing / alignment of the icons will be tricky without using Stack, but it could be done with lots of fiddling around with padding/margin.
import 'package:flutter/material.dart';
final bool debug = false;
class RowColLayoutPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Row Col Layout'),
),
body: Column(
children: [
Container(
color: debug ? Colors.lightGreenAccent : null,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
flex: 1,
child: RowIcon(icon: Icons.lightbulb)
),
Expanded(
flex: 2,
child: RowText(text: 'Electricity')
)
],
),
),
RowDivider(),
Container(
color: debug ? Colors.lightGreenAccent : null,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
flex: 1,
child: RowIcon(icon: Icons.microwave_rounded,)
),
Expanded(
flex: 2,
child: RowText(text: 'Internet')
)
],
),
),
RowDivider(),
],
),
);
}
}
class RowIcon extends StatelessWidget {
final IconData icon;
RowIcon({this.icon});
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 2),
decoration: BoxDecoration(
border: debug ? Border.all() : null
),
child: Icon(icon, size: 80,)
);
}
}
class RowText extends StatelessWidget {
final String text;
RowText({this.text});
#override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
border: debug ? Border.all() : null
),
child: Text(text, style: TextStyle(fontSize: 40))
);
}
}
class RowDivider extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Divider(thickness: 1, color: Colors.blue, indent: 15, endIndent: 15,);
}
}

Related

No errors in Flutter but custom widgets not showing

I am trying to make a ResuseableCard custom widget and IconContent custom widget.
Problem: Reuseable card are empty. IconContent is not showing inside ReusueableCard
What I have tried:
I also failed at creating a cardChild property within Reuseable Card that has a Column containing the icon, sized box and label. I did not see any errors when I tried this but the cards remained empty!
What has worked: When everything is spelled out within ReuseableCard (no separate IconContent widget or cardChild property) it works. But then all the cards look the same.
Another thing that works is to separately code each card. I don't want repeated code. The tutorial I follow works so why doesn't my code?
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
const labelColor = Color(0xFF76FF03);
class InputPage extends StatefulWidget {
#override
_ InputPageState createState() => _InputPageState();
}
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF0A0E21),
title: Text('BMI CALCULATOR'),
centerTitle: true,
),
body: Column(
children: [
Expanded(
child: Row(children: [
Expanded(
child: ReuseableCard(
colour: activeCardColor,
cardChild: IconContent(FontAwesomeIcons.venus, 'Female'),
),
),
Expanded(
child: ReuseableCard(
colour: activeCardColor,
cardChild: Column(children: [
Icon(FontAwesomeIcons.mars, size: 80.0),
SizedBox(height: 15.0),
Text('Male',
style: TextStyle(
fontSize: 18.0, color: (Color(0xFF8d8E98)))),
]),
)),
])),
Expanded(
child: ReuseableCard(colour: activeCardColor),
),
Expanded(
child: Row(
children: [
Expanded(
child: ReuseableCard(colour: activeCardColor),
),
Expanded(
child: ReuseableCard(colour: activeCardColor),
)
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: 80.0,
)
],
));
}
}
class ReuseableCard extends StatelessWidget {
ReuseableCard({#required colour, cardChild});
Color? colour;
Widget? IconContent;
#override
Widget build(BuildContext context) {
return Container(
child: IconContent,
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: Color(0xFF1D1E33),
borderRadius: BorderRadius.circular(10.0)));
}
}
class IconContent extends StatelessWidget {
IconData? data;
String label = 'label';
IconContent(data, label);
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(data, size: 80.0),
SizedBox(height: 15.0),
Text(label,
style: TextStyle(
fontSize: 18.0,
color: labelColor,
))
]);
}
}
You have not defined cardChild properly and are not calling it in the ReuseableCard. I have made all the fields as required in the below code.
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
const bottomContainerHeight = 80.0;
const activeCardColor = Color(0xFF1D1E33);
const bottomContainerColor = Color(0xFFEB1555);
const labelColor = Color(0xFF76FF03);
class InputPage extends StatefulWidget {
#override
_ InputPageState createState() => _InputPageState(); }
class _InputPageState extends State<InputPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Color(0xFF0A0E21),
title: Text('BMI CALCULATOR'),
centerTitle: true,
),
body: Column(
children: [
Expanded(
child: Row(children: [
Expanded(
child: ReuseableCard(
colour: activeCardColor,
cardChild: IconContent(data:FontAwesomeIcons.venus,label: 'Female'),
),
),
Expanded(
child: ReuseableCard(
colour: activeCardColor,
cardChild: Column(children: [
Icon(FontAwesomeIcons.mars, size: 80.0),
SizedBox(height: 15.0),
Text('Male',
style: TextStyle(
fontSize: 18.0, color: (Color(0xFF8d8E98)))),
]),
)),
])),
Expanded(
child: ReuseableCard(colour: activeCardColor),
),
Expanded(
child: Row(
children: [
Expanded(
child: ReuseableCard(colour: activeCardColor),
),
Expanded(
child: ReuseableCard(colour: activeCardColor),
)
],
),
),
Container(
color: bottomContainerColor,
margin: EdgeInsets.only(top: 10.0),
width: double.infinity,
height: 80.0,
)
],
));
}
}
class ReuseableCard extends StatelessWidget {
ReuseableCard({#required this.colour,#required this.cardChild});
Color? colour;
Widget? cardChild;//cardChild defined here so the ReuseableCard can use it
#override
Widget build(BuildContext context) {
return Container(
child: cardChild,//called here
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: Color(0xFF1D1E33),
borderRadius: BorderRadius.circular(10.0)));
}
}
class IconContent extends StatelessWidget {
IconData? data;
String? label;
IconContent({#required this.data, #required this.label});
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(data, size: 80.0),
SizedBox(height: 15.0),
Text(label??"label",
style: TextStyle(
fontSize: 18.0,
color: labelColor,
))
]);
}
}
I think this will do.
class ReuseableCard extends StatelessWidget {
ReuseableCard({Key? key,required this.colour, this.cardChild}) : super(key: key);
final Color colour;
final Widget? cardChild;
#override
Widget build(BuildContext context) {
return Container(
child: cardChild?? const SizedBox(),
margin: EdgeInsets.all(15.0),
decoration: BoxDecoration(
color: Color(0xFF1D1E33),
borderRadius: BorderRadius.circular(10.0)));
}
}
when you use
required
you don't have to say it can be null, also don't user widgets directly if it can be null.
if you want more help with your design, provide us your UI design what you trying to create.

How to make an ExpansionTile trailing Icon spin?

I've created an expansiontile and I've changed the original trailing icon to an svg icon which I customized. Anytime I click the expansion tile... everything works but the new svg trailing icon doesnt spin like the original trailing icon. Please how do I fix this?
code below
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
class ExpansionTileCard extends StatelessWidget {
final String toptitle;
final List<Widget> children;
const ExpansionTileCard({Key key, this.toptitle, this.children})
: super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
decoration: new BoxDecoration(
border:
new Border(bottom: new BorderSide(color: Colors.green))),
child: new Row(
children: [
new Expanded(
flex: 9,
child: new Container(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ExpansionTile(
title: Text(
toptitle,
style: TextStyle(
color: Colors.black,
letterSpacing: -1,
fontSize: 19,
fontWeight: FontWeight.bold),
),
children: children,
childrenPadding: EdgeInsets.fromLTRB(0, 0, 0, 20),
iconColor: Colors.green,
trailing: SvgPicture.asset(
'assets/icons/textmessage.svg',
height: 30,
),
),
],
),
),
)
],
),
),
],
),
);
}
}
While we don't provide trailing on ExpansionTile it uses the default behavior of it.
We are passing a widget into trailing and we need to control it. In order to do that, we need to check if ExpansionTile is expanded or not, the onExpansionChanged call back will provide this value. To handle animation we can use many widgets like Transform, RotatedBox, AnimatedRotation... In this ExpansionTileCard widget will be extended from StatefulWidget .
Steps
convert to StatefulWidget
create a bool inside state class to check the Expanded-state.
bool _isExpanded = false;
change value on onExpansionChanged
onExpansionChanged: (value) {
setState(() {
_isExpanded = value;
});
},
assign your widget on trailing by wrapping animation widget or just check the state return two widget
_isExpanded? ExpandedWidget:NormalViewWidget()
trailing: AnimatedRotation( /// you can use different widget for animation
turns: _isExpanded ? .5 : 0,
duration: Duration(seconds: 1),
child: CustomWidget()// your svgImage here
),
Widget State
class _ExpansionTileCardState extends State<ExpansionTileCard> {
bool _isExpanded = false;
#override
Widget build(BuildContext context) {
return Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.green))),
child: Row(
children: [
Expanded(
flex: 9,
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ExpansionTile(
onExpansionChanged: (value) {
setState(() {
_isExpanded = value;
});
},
title: Text(
widget.toptitle,
style: TextStyle(
color: Colors.black,
letterSpacing: -1,
fontSize: 19,
fontWeight: FontWeight.bold),
),
children: widget.children,
childrenPadding: EdgeInsets.fromLTRB(0, 0, 0, 20),
iconColor: Colors.green,
trailing: AnimatedRotation(
turns: _isExpanded ? .5 : 0,
duration: Duration(seconds: 1),
child: SvgPicture.asset(
'assets/icons/textmessage.svg',
height: 30,
),
),
],
),
),
)
],
),
),
],
),
);
}
}

How to wrap the Row according to child Text widget in Flutter

I have this piece of code inside a scaffold with SafeArea:
Column(
children: [Flexible(
fit: FlexFit.loose,
child: Container(
// width: 130,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [Icon(Icons.ac_unit), Text("Trending")],
),
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
color: Colors.grey[300]),
),
)]
)
Which gives the following result:
What I want to achieve is this:
How do I make the row warp around the text.
from the documentation
Wrap(
spacing: 8.0, // gap between adjacent chips
runSpacing: 4.0, // gap between lines
children: <Widget>[
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('AH')),
label: Text('Hamilton'),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('ML')),
label: Text('Lafayette'),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('HM')),
label: Text('Mulligan'),
),
Chip(
avatar: CircleAvatar(backgroundColor: Colors.blue.shade900, child: Text('JL')),
label: Text('Laurens'),
),
],
)
if you want to use that row just do
Row(
mainAxisSize: MainAxisSize.min
children: [
...
])
replace that Chip() with the above row
Edit:
replace the Chip() with that _buildChip() custom widget something like this, It should give you a better control over the widget
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(
home: MyPage(),
));
}
class MyPage extends StatelessWidget {
Widget _buildChip() {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: Colors.grey.withOpacity(.4) ),
child: InkWell(
highlightColor: Colors.blue.withOpacity(.4),
splashColor: Colors.green,
borderRadius: BorderRadius.circular(20),
onTap: () {
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 7),
child: Row(
mainAxisSize: MainAxisSize.min,
children:[
Icon(Icons.ac_unit, size: 14),
SizedBox(width: 10),
Text("Trending")
]),
),
),
);
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Wrap(
spacing: 8.0, // gap between adjacent chips
runSpacing: 4.0, // gap between lines
children: <Widget>[
_buildChip(),
_buildChip(),
_buildChip(),
_buildChip(),
_buildChip(),
],
)
);
}
}
let me know if It is what you want, so that I edit that answer
Take a look at this example. You should be using Wrap and RichText to achieve this design. Not Flexible, because it will take all the available space.
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 {
final String title;
MyHomePage({Key? key, required this.title}) : super(key: key);
#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: Wrap(children: [
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: Colors.grey[300]),
child: RichText(
text: TextSpan(
children: [
WidgetSpan(
child: Icon(Icons.ac_unit, size: 14),
),
TextSpan(
text: "Trending",
),
],
),
),
),
SizedBox(width: 5,),
Container(
padding: EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20), color: Colors.grey[300]),
child: RichText(
text: TextSpan(
children: [
WidgetSpan(
child: Icon(Icons.ac_unit, size: 14),
),
TextSpan(
text: "Trending",
),
],
),
),
)
]),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}

How to center AppBar and how to reduce leading icon size in PrefrerredSize?

How to center whole AppBar and how to reduce leading icon?
I tried with Center widget and Column with mainAxisAlignment.center not working.
And I tried add width and height to leading icon container.but nothing is working
appBar: PreferredSize(
child: AppBar(
leading: Container(
decoration: BoxDecoration(..),
child: Icon(..),
),
title: TextFormField(
...
),
actions: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
...
),
CupertinoSwitch(
...
)
],
)
],
),
preferredSize: Size.fromHeight(80.0)),
As shown here.
as an option
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
appBar: AwesomeAppBar(height: 80),
),
);
}
}
class AwesomeAppBar extends PreferredSize {
final double height;
const AwesomeAppBar({Key key, #required this.height});
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, snapshot) {
return Container(
padding: EdgeInsets.only(top: MediaQuery.of(context).padding.top),
height: height,
color: Theme.of(context).primaryColor,
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.all(16),
child: Icon(
Icons.arrow_back,
color: Colors.white,
),
),
Expanded(
child: Container(
height: 32,
alignment: Alignment.centerLeft,
padding: EdgeInsets.symmetric(horizontal: 16),
margin: EdgeInsets.only(right: 16),
decoration: ShapeDecoration(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
color: Colors.white,
),
child: Text('Search'),
),
),
SwitchWithText(),
SizedBox(width: 16),
],
),
);
});
}
#override
Size get preferredSize => Size.fromHeight(height);
}
class SwitchWithText extends StatefulWidget {
#override
_SwitchWithTextState createState() => _SwitchWithTextState();
}
class _SwitchWithTextState extends State<SwitchWithText> {
#override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Text('Online', style: TextStyle(color: Colors.white)),
CupertinoSwitch(
value: true,
onChanged: (b) {},
activeColor: Colors.lightBlueAccent,
),
],
);
}
}

'constraints.hasBoundedWidth': is not true

Following is my code
main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: "Student Info",
debugShowCheckedModeBanner: false,
home: SafeArea(
child: HomePage(),
),
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ListView(
children: <Widget>[StudentScreenAppBar(), StudentGraduateList()],
),
);
}
}
class StudentScreenAppBar extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
AppBar(
leading: IconButton(
icon: Icon(
Icons.arrow_back_ios,
color: Colors.black,
size: 20.0,
),
onPressed: () {}),
centerTitle: true,
title: Text(
"Student Info",
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
IconButton(
icon: Icon(
Icons.settings,
size: 20.0,
color: Colors.black,
),
onPressed: () {}),
// SizedBox(width: 10.0,),
IconButton(
icon: Icon(
Icons.settings_ethernet,
color: Colors.black,
size: 20.0,
),
onPressed: () {})
],
elevation: 0.0,
backgroundColor: Colors.white,
),
Container(
decoration: BoxDecoration(border: Border.all(color: Colors.black)),
padding: const EdgeInsets.fromLTRB(8.0, 2.0, 8.0, 2.0),
child: Image.asset(
"images/isdi_school.png",
width: 40.0,
height: 15.0,
fit: BoxFit.contain,
))
],
);
}
}
class StudentGraduateList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
yearListForUgPg("Under Graduate"),
yearListForUgPg("Post Graduate")
],
),
);
}
Widget yearListForUgPg(String graduationName) {
return Column(
children: <Widget>[
Container(
padding: const EdgeInsets.fromLTRB(25.0, 4.0, 25.0, 4.0),
child: Text(
graduationName,
style:
TextStyle(color: Colors.white, fontFamily: "suisseintlMedium"),
),
decoration: BoxDecoration(color: Colors.black),
),
ListView.builder(
shrinkWrap: true,
itemBuilder: (context, index) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"2018",
style: TextStyle(
fontFamily: "okomitoBold", color: Colors.black),
),
Icon(Icons.arrow_forward)
],
);
},
itemCount: 10,
)
],
);
}
}
The ListView Widget does not get displayed. If I comment the ListView then the code works fine and I am able to see the UI. I tried wrapping the ListView in Expanded and Flexible Widget but it does not work.
If I uncomment the ListView then I get error saying 'constraints.hasBoundedWidth': is not true. I am trying to achieve something like this in my UI:
![Image][1]
Simply wrap your -Column in Expanded Widget: that way your Column will try to occupy available space in the parent Row.
Updated code:
class StudentGraduateList extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(child: yearListForUgPg("Under Graduate")),
Expanded(child: yearListForUgPg("Post Graduate"))
],
),
);
}