What is the easy way to create reusable widgets in flutter? - 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.

Related

Navigator.pushnamed doesn't work in flutter

I'm trying to write a page to show the elements of a music album uploaded to Firestore, but when I navigate to another page using Navigator.pushNamed, passing the album name as an argument, I get an error:
FlutterError (Could not find a generator for route RouteSettings("/album", Item1) in the _WidgetsAppState.
First page code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:soundstream/album.dart';
import 'package:soundstream/albumPage.dart';
import 'package:soundstream/songList.dart';
class StartPage extends StatefulWidget {
#override
State<StartPage> createState() => _StartPageState();
}
class _StartPageState extends State<StartPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: ListView(
children: <Widget>[
SizedBox(height: 32.0),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'Hi!',
style: TextStyle(
color: Colors.white,
fontSize: 24.0),
),
],
),
SizedBox(height: 32.0),
Text(
'Items',
style: TextStyle(
color: Colors.white,
fontSize: 38.0),
),
SizedBox(height: 16.0),
AlbumList((album) => {
Navigator
.pushNamed(context, '/album', arguments: album)
}),
],
),
),
],
),
);
}
}
Second page code:
import 'package:flutter/material.dart';
import 'package:soundstream/songList.dart';
class AlbumPage extends StatefulWidget {
final album;
final Function callback;
AlbumPage(this.album, this.callback);
#override
_AlbumPageState createState() => _AlbumPageState();
}
class _AlbumPageState extends State<AlbumPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: EdgeInsets.fromLTRB(0, 50, 0, 0),
child: Column(
children: [
Text(
widget.album,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 38.0),
),
SizedBox(height: 16.0),
Padding(
padding: EdgeInsets.fromLTRB(15, 0, 0, 15),
child:
Text(
'Tracklist',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 38.0),
)
),
],
)),
);
}
}
How can i fix it? I would really appreciate an explanation!
Make sure you you register you the page that you want to navigate to in the material app routes https://docs.flutter.dev/development/ui/navigation#using-named-routes

How to center a Row containing wrapped text within a Column

I am having difficulty figuring how to get a Row, which contains wrapped text, to appear centered in a Column.
The issue seems to be that Flexible (or Expanded for that matter) causes the Text widget to consume the entire remaining horizontal space in the Row. This seems fine for text layout purposes, i.e., determining the needed height for the text. However, it also seems to me that is should be possible that once the text has been laid out, the bounds of its widget can be "shrunk" to require only the minimum width necessary. (Notice the difference of width/space within the red bounding box in the images below.)
Is it possible to achieve this in Flutter? What am I overlooking?
I have searched high and low on SO and haven't found this specific question.
The closest related might be this but it's difficult to be certain the way that question was asked. (And it did not receive any answers.)
What I am seeing
What I would like to see
What I have tried
Several permutations of Flexible and Expanded, around the Text, Row, and Column in various combinations
Several different values for fit and flex (with Flexible)
IntrinsicWidth parent on Column
softWrap
Code
(Based on the "Counter" sample from DartPad.)
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
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: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent),
),
width: 300,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'\u{1F603}',
style: TextStyle(
fontSize: 24.0,
),
),
Flexible(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: const Text(
'Some text that ends up taking_two_lines',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
),
],
),
],
),
),
);
}
}
Welp, as I was typing up this question, I discovered the solution, so I may as well write it up for others.
The trick was to use the textWidthBasis argument of Text and set it to TextWidthBasis.longestLine.
If you has parent widget set yours to center too
In my case i set My Colum(mainAlignment to center and it is work for me)
Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent),
),
alignment: Alignment.center,
width: 300,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'\u{1F603}',
style: TextStyle(
fontSize: 24.0,
),
),
Flexible(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.red),
),
child: const Text(
'Some text that ends up taking_two_lines',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
),
],
),
],
),
),
Try below code hope its help to you I have try same as your expected design
Your Widget:
Scaffold(
appBar: AppBar(
actions: [
const Center(
child: Padding(
padding: EdgeInsets.all(8),
child: Text(
'Flutter',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
),
],
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const SizedBox(
width: 50,
),
const Text(
'\u{1F603}',
style: TextStyle(
fontSize: 24.0,
),
),
Expanded(
child: const Text(
'Some text that ends up taking_two_lines',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
),
),
),
],
),
],
),
),
Result Screen->

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

Flutter widgets best practices: Inner Class vs Function

I am a Java developer and currently learning about Flutter/Dart. I am an adept of clean code with small functions and some widget examples just scare the s*** out of me.
I am trying to implement a Card widget with some transaction information (price, title and date). Currently the code looks like this:
class TransactionCard extends StatelessWidget {
final Transaction _transaction;
TransactionCard(this._transaction);
#override
Widget build(BuildContext context) {
return Container(
child: Card(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
_PriceContainer(_transaction.amount),
_DetailContainer(_transaction.title, _transaction.date),
],
),
),
);
}
}
// Inner Widgets
class _PriceContainer extends Container {
_PriceContainer(double amount)
: super(
margin: EdgeInsets.symmetric(
vertical: 10,
horizontal: 15,
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.purple,
width: 2,
),
),
padding: EdgeInsets.all(10),
child: Text(
amount.toString(),
style: _amountTextStyle(),
),
);
}
class _DetailContainer extends Container {
_DetailContainer(String title, DateTime date)
: super(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
title,
style: _titleTextStyle(),
),
Text(
date.toString(),
style: _dateTextStyle(),
),
],
),
);
}
// Text styles
TextStyle _amountTextStyle() {
return TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.purple,
);
}
TextStyle _titleTextStyle() {
return TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18,
);
}
TextStyle _dateTextStyle() {
return TextStyle(color: Colors.grey);
}
I have used two approaches:
For the inner widgets I extended Containers and gave then specific styling.
For the text styles I created a function returning the desired style.
Is there an approach preferable to the other? A third one? Is there a bad practice to create multiple Widgets on the same file?
Composition > inheritance
As mentioned in the comments and in the Flutter documentation, you should always compose widgets instead of inheriting from e.g. a Container.
In your case, this would look like this:
class _PriceContainer extends StatelessWidget {
final double amount;
const _PriceContainer({
Key key,
this.amount,
}) : super(key: key);
#override
Widget build(BuildContext context) => Container(
margin: const EdgeInsets.symmetric(
vertical: 10,
horizontal: 15,
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.purple,
width: 2,
),
),
padding: EdgeInsets.all(10),
child: Text(
amount.toString(),
style: _amountTextStyle,
),
);
}
This is analogous for your other widgets.
Top-level functions
Declaring top-level functions is generally fine, however, in this case, you should really define a top-level property instead - preferably declare a const to take advantage of compile-time constants:
const _amountTextStyle = TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.purple,
);
You should be able to apply the same to your other text styles.

TextFormField not appearing in Simulator

I've been trying to make the TextFormField ('email:') appear in my Simulator, but it's not appearing in my Simulator as following:
However when I make changes to any other things, it does change, so the Simulator is not a problem.
This is my login_page.dart file:
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget{
#override
State createState() => new LoginPageState();
}
class LoginPageState extends State<LoginPage>{
#override
Widget build(BuildContext context){
return new Scaffold(
appBar: AppBar(
title: new Text("SMART ID", textAlign: TextAlign.center, style: TextStyle(fontFamily: 'Open Sans', fontWeight: FontWeight.bold)),
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset(
"assets/arrowPNG.png",
scale: 8.0,
)
)
),
backgroundColor: Colors.transparent,
body: Stack(
children: <Widget>[
Container(
alignment: Alignment.center,
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage('assets/background.png'),
fit: BoxFit.cover,
),
),
),
Positioned(
width: MediaQuery.of(context).size.width,
top: MediaQuery.of(context).size.width * 0.30,
child: Container(
margin: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image.asset('assets/arrowPNG.png', scale: 2.5),
SizedBox(height: 20,),
Text("SMARTID", style: TextStyle(
fontSize: 30, color: Colors.black, fontFamily: 'Open Sans', fontWeight: FontWeight.bold,
),
),
Text("Attendance & Wallet Monitoring", style: TextStyle(
fontSize: 16, color: Colors.black, fontFamily: 'Open Sans', fontWeight: FontWeight.normal,
)
)
],
),
),
),
Positioned(
width: MediaQuery.of(context).size.width,
top: MediaQuery.of(context).size.width * 0.85,
child: Container(
margin: EdgeInsets.all(16.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Version 1.0", style: TextStyle(
fontSize: 16, color: Colors.black, fontFamily: 'Open Sans', fontWeight: FontWeight.normal,
)
)
],
)
)
)
],
),
);
}
}
class LoginForm extends StatefulWidget{
#override
LoginFormState createState(){
return LoginFormState();
}
}
class LoginFormState extends State<LoginForm>{
final formKey = GlobalKey<FormState>();
String _username, _password;
#override
Widget build(BuildContext context){
body: Card(
child: Padding(
padding: EdgeInsets.all(8.0),
child: Form(
key: formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
labelText: 'Username:'
),
validator: (input) => !input.contains('0') ? 'Username cannot be blank' : null,
onSaved: (input) => _username = input,
),
],
),
),
),
);
}
}
How do I resolve this? Thanks in advance!
You are right, Simulator is not a problem. The problem is in your code. You have correctly created the LoginPage. To correct the LoginForm widget, in your LoingFormState's build function replace:
body: Card(
// your usual code that you have above
)
with
return Card(
// your usual code that you have above
)
Also you have not used the LoginForm Widget in the LoginPage, and that is the reason the form is not visible. Simply, creating a widget doesn't include the widget on any screen, you have to use the widget.
You can do that by adding the widget inside the body section of LoginPageState's build function. To use the widget type
body: Stack(
children: <Widget>[
// your other widgets
LoginForm(),
]
)
like you do for any other widget.
This should solve your problem