Difference between implement pieces of UI in var and final variables - flutter

This example from Google shows how you can store pieces of UI in variables.
var stars = Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.green[500]),
Icon(Icons.star, color: Colors.black),
Icon(Icons.star, color: Colors.black),
],
);
final ratings = Container(
padding: EdgeInsets.all(20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
stars,
Text(
'170 Reviews',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w800,
fontFamily: 'Roboto',
letterSpacing: 0.5,
fontSize: 20,
),
),
],
),
);
Note that the stars piece of UI is stored in a var variable while the ratings piece of UI is stored in a final variable.
var stars = Row(...);
final ratings = Container(...);
My questions are:
What is the motivation behind this difference?
When to store a piece of UI in a var variable and when in a final variable?

As the name suggest, var means something whose value can be changed later on, and final is something whose value once assigned will never be changed. So, you can pretty much use any of them, it all depends on your need.
var widget = Container(color: Colors.black);
widget = Container(color: Colors.white); // no problem
final widget2 = Container(color: Colors.black);
widget2 = Container(...)// error you can't assign anything to this widget again

Related

There is an error even though the value type has no error (Invalid constant value)

List<MaterialColor?> changeColor = [
Colors.red,
Colors.blue,
Colors.yellow,
Colors.green,
Colors.pink,
];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Mohammed is coming back ',
style: TextStyle(
color: changeColor[_counter],
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
I made a list consisting of a set of colors and I want to give it to the color but it keeps giving me this error, even though I gave the list type the same as the color type
_counter value will change and get on read time. That's why Text widget can not be const. Remove const from Text.
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Mohammed is coming back ',
style: TextStyle(
color: changeColor[_counter],
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
],
),
),
You can more about
const on dart.dev and
a good question on difference between the "const" and "final" keywords in Dart?

Text overflowing in row when Stack is a parent

I am trying to create a row widget with two texts widgets inside, however the text keeps overflowing out of screen instead of going right under it. Why is this happening and how can I avoid this?
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
resizeToAvoidBottomInset: false,
body: Container(
width: double.infinity,
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 40.0),
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/main_cover.jpg"),
fit: BoxFit.cover)),
child: Stack(children: [
Padding(
padding: const EdgeInsets.fromLTRB(20,0,20,0),
child: InkWell(
onTap: () => _launchURL(),
child: Container(
child: Row(
children: [
DefaultText(fontSize: 12.0, color: Colors.white, weight: FontWeight.normal, textData: "By clicking the \"Register\", button confirm that you accept the application"),
DefaultText(fontSize: 12.0, color: Colors.blue, weight: FontWeight.normal, textData: "terms of service and privacy policy."),
],
),
)),
),
]),
),
));
}
}
Use Flexible as below:
Row(
children: [
Flexible(
child:DefaultText(fontSize: 12.0, color: Colors.white, weight: FontWeight.normal, textData: "By clicking the \"Register\", button confirm that you accept the application"),
),
Flexible(
child:
DefaultText(fontSize: 12.0, color: Colors.blue, weight: FontWeight.normal, textData: "terms of service and privacy policy."),
),
],
)
This will warp your text.
But I suggest you should use RichText.
RichText(
text: TextSpan(
text: 'By clicking the \"Register\", button confirm that you accept the application',
style: TextStyle(
color: Colors.black, fontSize: 18),
children: <TextSpan>[
TextSpan(text: 'Terms and policy',
style: TextStyle(
color: Colors.blueAccent, fontSize: 18),
recognizer: TapGestureRecognizer()
..onTap = () {
// navigate to desired screen
}
)
]
),
),
Update:
You can also use library html https://pub.dev/packages/html
try wrapping your children in Flexible() widget
Like this:
Flexible(
Text()
),
A row aligns it's children horizontally, which means your first DefaultText widget is rendered and the second one on the right of it.
What you can do is wrap both children in Expanded and make the text overflow fading and use Text instead of DefaultText :
Stack(children: [
Padding(
padding: const EdgeInsets.fromLTRB(20,0,20,0),
child: InkWell(
onTap: () => _launchURL(),
child: Container(
child: Row(
children: [
Expanded(child:Text(style:TextStyle(fontSize: 12.0, color: Colors.white, fontWeight: FontWeight.normal,overflow: TextOverflow.fade),"By clicking the \"Register\", button confirm that you accept the application")),
Expanded(child:Text(style:TextStyle(fontSize: 12.0, color: Colors.blue, fontWeight: FontWeight.normal,overflow: TextOverflow.fade) ,"terms of service and privacy policy.")),
],
),
)),
),
]),
You should wrap your Container in a Flexible to let your Row know that it's ok for the Container to be narrower than its intrinsic width. Expanded will also work.
Use Flexible in the Row.
Example:Row(
children: [
Flexible(
child: DefaultText(
fontSize: 12.0,
color: Colors.white,
weight: FontWeight.normal,
textData:
"By clicking the \"Register\", button confirm that you accept the application"),
),
Flexible(
child: DefaultText(
fontSize: 12.0,
color: Colors.blue,
weight: FontWeight.normal,
textData: "terms of service and privacy policy."),
)
],
)

Building a Card with Images problem with overflow

I'm currently building products from my store in my products screen, What I'm attempting to do is, create a GridView and a card for each product. I'm having problem with the overflow from the image.
What I want to look like:
How it is going:
My code for the card:
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:loja_virtual_nnananene/helpers/color_select.dart';
import 'package:loja_virtual_nnananene/models/product.dart';
class ProductListTile extends StatelessWidget {
const ProductListTile(this.product);
final Product product;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/product', arguments: product);
},
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
alignment: Alignment.center,
children: [Image.network(product.images!.first)],
),
Text(
product.name,
style: GoogleFonts.firaCode(
textStyle:
TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
),
Text('R\$ ${product.basePrice.toStringAsFixed(2)}',
style: GoogleFonts.firaCode(
textStyle: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w800,
color: ColorSelect.cprice)))
],
),
));
}
}
Try to add your Card Widget inside SingleChildScrollView() Widget :
SingleChildScrollView(
child:Card(),
),
There is no need Stack widget in your code. Try this:
If you want u can remove ConstrainedBox, but image size will be different according to its size.
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:loja_virtual_nnananene/helpers/color_select.dart';
import 'package:loja_virtual_nnananene/models/product.dart';
class ProductListTile extends StatelessWidget {
const ProductListTile(this.product);
final Product product;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.of(context).pushNamed('/product', arguments: product);
},
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ConstrainedBox(
constraints: const BoxConstraints(
minHeight: 50.0,
maxHeight:300.0
),
child: Image.network(product.images!.first),
),
Text(
product.name,
style: GoogleFonts.firaCode(
textStyle:
TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
),
Text('R\$ ${product.basePrice.toStringAsFixed(2)}',
style: GoogleFonts.firaCode(
textStyle: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w800,
color: ColorSelect.cprice)))
],
),
));
}
}
Are you using SliverGridDelegateWithFixedCrossAxisCount? If yes, it has a property aspectRatio which is default to 1.0 (height will be same as width). Try to make it 0.7 or something and your error will be gone in that case.
You can achieve the first image this way
Container(
decoration: Boxdecoration(
color: Colors.white,
borderRadius: borderRadius.circular(8),
boxShasow: [
BoxShadow(
offset: Offset(10,17),
blurRadius:17,
spreadRadius: -23,
color: Colors.grey,),],),
child: Padding(
padding: const EdgeInset.all(10.0),
child: Column(
Image.network(
"your url",
width: width of choice,
height: height of choice,
),
Text(
"product name",
testAlign:TestAlign.left,
style:(your style),
),
Row(
children:<Widget>[
Text(
"product amount",
testAlign:TestAlign.left,
style:(your style),
),
Expanded(
child:Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Icon(
Icons.heart_outlind,
color:Colors.blue,
size:24,
),
SizedBox(width:5),
],),),
],),),),

What is the easy way to create reusable widgets in flutter?

Container(
child: Column(
children: <Widget>[
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 10.0),
child: Text("Random Text",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.black)),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all(10.0),
child: Text("Owner",
style: TextStyle(
fontWeight: FontWeight.bold,
color: Colors.grey)),
),
],
),
),
I don't know if it's an easy way. But for a simple reusable widget, you can place your widget inside a StatelessWidget or a StatefulWidget.
Here's the example:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
children: <Widget>[
MyReusableWidget('Nikola Tesla', 'Owner'), //Input the name and role variable when you call the widget
MyReusableWidget('Albert Einstein', 'Developer'),
MyReusableWidget('Isaac Newton', 'Technician'),
],
),
),
);
}
}
class MyReusableWidget extends StatelessWidget {
final String name; // provide a place for the input's data
final String role;
MyReusableWidget(this.name, this.role);
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.only(left: 10.0),
child: Text(
name, // This is where you place your 'name' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.black),
),
),
Container(
alignment: Alignment.topLeft,
padding: EdgeInsets.all(10.0),
child: Text(
role, // This is where you place your 'role' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.grey),
),
),
],
),
);
}
}
I'm creating a widget called MyReusableWidget. I am gonna call that widget inside my MyApp 3 times. And then each widget should provide different names and roles.
So inside my MyReusableWidget, I provide two String data-types called name and role to store my data when I call the widget.
final String name; // provide a place for the input's data
final String role;
MyReusableWidget(this.name, this.role);
And then I want to place my name and role variable inside a Text widget:
child: Text(
name, // This is where you place your 'name' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.black),
),
and:
child: Text(
role, // This is where you place your 'role' data
style: TextStyle(
fontWeight: FontWeight.bold, color: Colors.grey),
),
After that, inside my MyApp widget, I can call MyReusableWidget as much as I want and provide different name and role value on each widget.
Column(
children: <Widget>[
MyReusableWidget('Nikola Tesla', 'Owner'), //Input the name and role variable when you call the widget
MyReusableWidget('Albert Einstein', 'Developer'),
MyReusableWidget('Isaac Newton', 'Technician'),
],
),
Result:
And that's it.
You can store any kind of data-type on it (String, int, double, etc).
I hope it will be helpful.

Space two objects within a row in Flutter

I know similar questions have been posted here but nothing I've found so far has helped me with my problem. I'm a beginner with Flutter so I need a bit of help. I am trying to build a simple weather app. I want to position the days of the week and the highs/lows of that day so that they sit as far apart as possible and both edges line up with each other. Currently, my app looks this (I added the red container to help understand).. The day of the week and temperature are hugging each other which is what I'm trying to fix.
I have tried using mainAxisAlignment.spaceEvenly, spaceBetween, and spaceAround but none of those move the text at all. I've tried using Spacer() but that makes the temperatures disappear.
I have a separate class to build each day because I'm pulling from an api. That class looks like this:
class WeatherReport extends StatelessWidget {
final String _day;
final String _tempMax;
final String _tempMin;
WeatherReport(this._day, this._tempMax, this._tempMin);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 0, 0),
child: Row(
children: <Widget>[
Text(_day, style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.w300
)
),
Container(
color: Colors.red,
child: Row(children: <Widget>[
Text(_tempMax + " | ", style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.w300
)
),
Opacity(
opacity: 0.5,
child: Text(_tempMin, style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.w300
)
),
),
],),
),
],
),
);
}
}
I call this class in my main build file. Here I created a column to house each row that is created by the previous class. That code looks like this:
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
WeatherReport(days[0], '${(forecast.days[0].main.tempMax).round()}º', '${(forecast.days[1].main.tempMin).round()}º'),
WeatherReport(days[1], '${(forecast.days[8].main.tempMax).round()}º', '${(forecast.days[9].main.tempMin).round()}º'),
WeatherReport(days[2], '${(forecast.days[16].main.tempMax).round()}º', '${(forecast.days[17].main.tempMin).round()}º'),
WeatherReport(days[3], '${(forecast.days[24].main.tempMax).round()}º', '${(forecast.days[25].main.tempMin).round()}º'),
WeatherReport(days[4], '${(forecast.days[32].main.tempMax).round()}º', '${(forecast.days[33].main.tempMin).round()}º'),
],
),
Any and all help would be greatly appreciated. I figure the answer is simple but I cannot figure out a solution.
You can wrap your Text Widget with an Expanded:
Expanded(
child: Text(
_day,
style: TextStyle(
color: Colors.white,
fontSize: 25,
fontWeight: FontWeight.w300,
),
),
),
This way the text and the temperature will be as far as possible of each other.