FirebaseAnimatedList doesn't return anything - flutter

I'm trying to write an app that will detect Barcode ID. Once detected, it will fetch value in my Firebase Database and display them inside my Widget. I want my widget to be dynamic since i don't know how many items could be inside each ID. So i tried using FirebaseAnimatedList class. Issue is i can't get my Widget show up in my page at all.
Here's my code
import 'dart:async';
import 'package:firebase_database/ui/firebase_animated_list.dart';
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:logistec/widget/result_page/productlist.dart';
class Scanning_Result_Page extends StatefulWidget {
Scanning_Result_Page(this.phyid, {Key? key}) : super(key: key);
String phyid;
#override
State<Scanning_Result_Page> createState() => _Scanning_Result_PageState();
}
class _Scanning_Result_PageState extends State<Scanning_Result_Page> {
late String productcode;
late String productname;
late int quantity;
late Query _ref =
FirebaseDatabase.instance.ref().child('Database').child(widget.phyid);
//firebase structure currently goes like this
//PHYID
//|---number
//|-----items_name
//|-----items_codes etc...
//Therefore i need it to first fetch PHYID
//then after that, use for loop from 0 to the full lenght of that ID
//
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
appBar: PreferredSize(
preferredSize: Size(40, 40),
child: AppBar(
backgroundColor: Colors.amber.shade400,
)),
body: Container(
height: double.infinity,
child: FirebaseAnimatedList(
shrinkWrap: true,
query: _ref.equalTo(widget.phyid),
itemBuilder: (BuildContext context, DataSnapshot snapshot,
Animation<double> animation, int index) {
Map database = snapshot.value as Map;
if (database != null) {
//result = key - phyid | value - 0?
return ProductList(
productcode: 'Test 1', //will change this later. just need it to work for now.
productname: 'Test 1',
serial: 'Test 1',
quantity: 1,
phyid_result: widget.phyid,
);
} else {
return Text("no data");
}
return CircularProgressIndicator();
},
),
),
);
}
}
And here's my Widget page. (I don't think it's related to my issue but i'll include them regardless.)
import 'package:flutter/material.dart';
class ProductList extends StatelessWidget {
ProductList({
Key? key,
required this.productcode,
required this.productname,
required this.quantity,
required this.phyid_result,
required this.serial,
}) : super(key: key);
final String productcode;
final String productname;
final int quantity;
final String phyid_result;
final String serial;
//The Look in my head
//Each Container will have
///////////////////////////////////
///ProductCode /
///ProductName /
/// /
/// ///////////////////////////////
/// Quantity/
/// ///////////////////////////////
final appBar = AppBar();
#override
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context);
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
resizeToAvoidBottomInset: false,
body: CustomScrollView(
scrollDirection: Axis.vertical,
slivers: [
SliverList(
delegate: SliverChildListDelegate([
Container(
padding: const EdgeInsets.all(15.0),
alignment: Alignment.center,
color: Colors.black,
height: 70.0,
child: Text(
phyid_result,
style: const TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
Container(
height: screenSize.size.height,
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade600)),
child: IntrinsicHeight(
child: Column(
//mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(5),
child: Text(
productcode,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
productname,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
serial,
style: const TextStyle(fontSize: 20),
),
),
Align(
alignment: Alignment.topRight,
child: Flexible(
fit: FlexFit.loose,
child: SizedBox(
width: 90,
child: Container(
decoration: BoxDecoration(
border:
Border.all(color: Colors.grey.shade200),
),
padding: EdgeInsets.all(5),
child: Text(
'Quantity : \n\v${quantity}',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.right,
)),
),
),
)
],
),
),
),
]))
],
),
),
);
}
}
The Scaffold part works. But everything inside FirebaseAnimated List all the way to CircularProgressIndicator doesn't work at all. It didn't even return if else statement. Just empty blank page with Scaffold.
The Widget itself will work fine if i remove everything out, and return only the ProductList widget itself. I tried searching on Google and didn't find anyone having issue like me. So i think i'm stuck. Does anyone know what could be the issue? Thanks for the assistance in advance!

So i solve my own issue.
It turns out that my Widget is the actual root cause. I don't think SliverList is playing well with FirebaseAnimatedList (maybe because they are doing essentially the same thing?) So i refactor and remove everything related to SliverList.
Widget build(BuildContext context) {
final screenSize = MediaQuery.of(context);
return Container(
decoration:
BoxDecoration(border: Border.all(color: Colors.grey.shade600)),
child: Column(
//mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
padding: EdgeInsets.all(5),
child: Text(
productcode,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
productname,
style: const TextStyle(fontSize: 20),
),
),
Container(
padding: EdgeInsets.all(5),
width: screenSize.size.width,
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey.shade200,
strokeAlign: StrokeAlign.inside)),
child: Text(
serial,
style: const TextStyle(fontSize: 20),
),
),
Align(
alignment: Alignment.topRight,
child: Flexible(
fit: FlexFit.loose,
child: SizedBox(
width: 90,
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey.shade200),
),
padding: EdgeInsets.all(5),
child: Text(
'Quantity : \n\v${quantity}',
style: TextStyle(fontSize: 18),
textAlign: TextAlign.right,
)),
),
),
)
],
),
);
Then i reimplemented it into my pages. Now it works as expected. all is well again!

Related

image_picker only showing images after hot reload. Flutter

I'm using the image_picker package to read images and take them using the camera.
I'm also using the provider package to manage the changes in results.
The app is about ads for selling stuff, when adding a new ad it is added successfully.
the problem is that the ad main image is not showing until I make a hot reload, and before reloading it shows an error.
Unable to load asset: /storage/emulated/0/Android/data/com.bkh.ads/files/Pictures/d2abeed9-3dfa-44b4-a032-ddefff58762e2465964411313585659.jpg
once I make a hot reload the ad image gets shown correctly and the error vanishes.
This is how I'm using image_picker:
Future _setAdMainImage() async {
String _method;
await showModalBottomSheet(
context: context,
builder: (context) => Container(
height: 105,
child: Column(
children: [
Container(
height: 50,
child: RaisedButton(
color: ColorPalette.PRIMARY_COLOR,
onPressed: () {
_method = 'Camera';
Navigator.of(context).pop();
},
child: Center(
child: Text(
'Image From Camera',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 18,
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
),
SizedBox(
height: 5,
),
Container(
height: 50,
child: RaisedButton(
color: ColorPalette.PRIMARY_COLOR,
onPressed: () {
_method = 'Gallery';
Navigator.of(context).pop();
},
child: Center(
child: Text(
'Image From Gallery',
textDirection: TextDirection.rtl,
style: TextStyle(
fontSize: 18,
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
),
],
),
),
);
if (_method != null) {
final _pickedFile = await _imagePicker.getImage(
source: _method == 'Camera' ? ImageSource.camera : ImageSource.gallery,
);
setState(() {
_image = File(_pickedFile.path);
});
_method = null;
}
}
This is how I'm adding the new ad object using the provider:
void addVehicleAd(VehicleAd vehicleAd) {
_vehicleAds.add(vehicleAd);
notifyListeners();
}
This is how I'm showing the results:
#override
Widget build(BuildContext context) {
_data = ModalRoute.of(context).settings.arguments as Map<String, dynamic>;
_ads = Provider.of<VehicleAds>(context).carAds;
return Scaffold(
body: ListView.builder(
itemCount: _ads.length,
itemBuilder: (context, index) => AdCard(
id: _ads[index].id,
image: _ads[index].image,
price: _ads[index].price,
label: _ads[index].label,
date: _ads[index].date,
),
),
);
}
And this is the AdCard widget:
class AdCard extends StatelessWidget {
final int id;
final String label, image;
final int price;
final DateTime date;
AdCard({
#required this.id,
#required this.label,
#required this.price,
#required this.image,
#required this.date,
});
#override
Widget build(BuildContext context) {
var _height = MediaQuery.of(context).size.height;
return InkWell(
child: Card(
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
side: BorderSide(
width: 2,
color: ColorPalette.ACCENT_COLOR,
),
),
child: Stack(
children: <Widget>[
Container(
height: 250,
width: double.infinity,
child: Hero(
tag: id,
child: Image(
image: AssetImage(image),
fit: BoxFit.cover,
),
),
),
Positioned(
right: 10,
bottom: 10,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black.withOpacity(.5),
),
child: Text(
label,
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(
height: 1,
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
Positioned(
left: 10,
bottom: 10,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black.withOpacity(.5),
),
child: Text(
'$price',
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 10),
child: Align(
alignment: Alignment.topCenter,
child: Container(
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Colors.black.withOpacity(.5),
),
child: Text(
'${date.day}/${date.month}/${date.year}',
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(
color: ColorPalette.WHITE_TEXT_ICONS_COLOR,
),
),
),
),
),
],
),
),
);
}
}
I have no idea where the wrong code is...
Any help would be appreciated
AssetImage widget gets from your asset resource.
For images taken by imagepicker, use Image.file.
Image.file(/* your file */, fit: BoxFit.cover,)

How to reduce the white space beside the drawer icon in Flutter?

In my flutter project, I have set one custom drawer.
Here's code for custom drawer-
class AppDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
double defaultScreenWidth = 400.0;
double defaultScreenHeight = 810.0;
ScreenUtil.instance = ScreenUtil(
width: defaultScreenWidth,
height: defaultScreenHeight,
allowFontScaling: true,
)..init(context);
return SizedBox(
width: MediaQuery.of(context).size.width * 0.70,
child: Drawer(
child: Container(
color: Colors.black87,
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
SizedBox(height: ScreenUtil.instance.setHeight(30),),
_createDrawerItem(
icon: Icons.keyboard_arrow_right,
text: 'English to Bangla',
onTap: () =>
Navigator.pushReplacementNamed(context, Routes.englishToBangla)),
Padding(
padding: EdgeInsets.only(left:ScreenUtil.instance.setWidth(20), right: ScreenUtil.instance.setWidth(20)),
child: Divider(
height: ScreenUtil.instance.setHeight(10),
color: Colors.grey,
),
),
],
),
),
),
);
}
Widget _createHeader() {
return DrawerHeader(
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: AssetImage('path/to/header_background.png'))),
child: Stack(children: <Widget>[
Positioned(
bottom: 12.0,
left: 16.0,
child: Text("Flutter Step-by-Step",
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
fontWeight: FontWeight.w500))),
]));
}
Widget _createDrawerItem(
{IconData icon, String text, GestureTapCallback onTap}) {
return ListTile(
title: Padding(
padding: EdgeInsets.only(left: ScreenUtil.instance.setWidth(10)),
child: Row(
children: <Widget>[
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.teal
),
child: Icon(icon, color: Colors.white,)
),
Padding(
padding: EdgeInsets.only(left: ScreenUtil.instance.setWidth(10)),
child: Text(text, style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: ScreenUtil.instance.setSp(14) ),),
)
],
),
),
onTap: onTap,
);
}
}
Here's code for the toolBar which is shown beside the drawer icon-
class SearchAppBar extends StatefulWidget implements PreferredSizeWidget {
final PatternCallback onPatternSelected;
SearchAppBar(this.onPatternSelected, {Key key})
: preferredSize = Size.fromHeight(90),
super(key: key);
#override
final Size preferredSize; // default is 56.0
#override
_SearchAppBarState createState() => _SearchAppBarState();
}
class _SearchAppBarState extends State<SearchAppBar> {
TextEditingController _searchTextController = TextEditingController();
#override
Widget build(BuildContext context) {
double defaultScreenWidth = 400.0;
double defaultScreenHeight = 810.0;
ScreenUtil.instance = ScreenUtil(
width: defaultScreenWidth,
height: defaultScreenHeight,
allowFontScaling: true,
)..init(context);
return Container(
color: Colors.white,
child: Row(
children: <Widget>[
Expanded(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(3),
),
child: Theme(
data:
Theme.of(context).copyWith(primaryColor: Color(0xFFff9900)),
child: TextFormField(
autofocus: false,
style: TextStyle(fontSize: ScreenUtil.instance.setSp(18)),
keyboardType: TextInputType.text,
controller: _searchTextController,
decoration: InputDecoration(
border: InputBorder.none,
hintText: 'Search for any word you want',
hintStyle:
TextStyle(fontSize: ScreenUtil.instance.setSp(16)),
contentPadding: EdgeInsets.symmetric(
vertical: 14,
horizontal: 10),
),
onChanged: (String value) {
widget.onPatternSelected(value);
},
),
),
),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(0),
),
child: InkWell(onTap: (){
if(_searchTextController.text.isNotEmpty) {
Navigator.of(context).push(MaterialPageRoute(builder: (context)=>WordDetailScreen(_searchTextController.text.toLowerCase())));
}
},
child: Icon(Icons.search, color: Colors.blue,))),
SizedBox(width: 15)
],
),
);
}
}
And then, in the class where I want to use this drawer, I have called inside Scaffold like below-
drawer: AppDrawer()
But the problem is this causing a white space beside the drawer icon like below image-
And I am having no idea from where this extra padding or margin is happening. So, I need a solution to reduce this extra white space beside the drawer icon.
You can use Transform.translate to move the search bar to the left:
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: Builder(builder: (context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () => Scaffold.of(context).openDrawer(),
);
}),
title: Transform.translate(
offset: Offset(-30.0, 0.0),
child: Text('this is the title') // here you can put the search bar
),
),
drawer: Drawer(
),
);
}
Just add a property called "titleSpacing" in your AppBar Tag,
Sample
appBar: AppBar(
titleSpacing: 0, //Add this line to your code
title: Text(widget.title),
leading: Icon(Icons.android),
),

Why the app is not rebuilding when I call setState?

I am developing an app with Flutter and I struggle with a problem: when I call the setState() method, the list I want to update does not update at all. I mean, it does not redrawing the widgets.
First of all, I have my list of custom widget, which is initialized with one element:
List<AdvFctPompa> _advFctPompaList = [AdvFctPompa(name: 'Bloc initial', temp: '4748425', imgPath: img2)];
My custom widget looks like this:
import 'package:flutter/material.dart';
class AdvFctPompa extends StatefulWidget {
final String imgPath;
final String name;
final String temp;
BoxConstraints constraint;
AdvFctPompa({
Key key,
this.imgPath,
#required this.name,
#required this.temp,
this.constraint,
}) : super(key: key);
#override
_AdvFctPompaState createState() => _AdvFctPompaState();
}
class _AdvFctPompaState extends State<AdvFctPompa> {
#override
Widget build(BuildContext context) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Column(
children: <Widget>[
Container(
height: widget.constraint.maxHeight * .6,
width: widget.constraint.maxWidth * .7,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
image: DecorationImage(
image: NetworkImage(widget.imgPath),
fit: BoxFit.cover,
),
),
),
SizedBox(height: 5),
Expanded(
child: Container(
height: widget.constraint.maxHeight,
width: widget.constraint.maxWidth * .7,
padding: const EdgeInsets.only(left: 5, right: 5),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 5),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
widget.name,
style: TextStyle(
fontSize: 15,
fontWeight: FontWeight.w500,
),
),
Text(
widget.temp + "ºC",
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: 15,
color: Colors.grey,
),
),
],
),
),
SizedBox(height: 5),
Container(
height: 30,
width: 100,
decoration: BoxDecoration(
image: DecorationImage(
image: ExactAssetImage('assets/images/img6.png'),
fit: BoxFit.cover,
),
),
)
],
),
),
)
],
),
);
}
}
Second, I have a button for adding a new element in list:
GestureDetector(
child: Visibility(
visible: _heightAnimation.value > 90,
child: Icon(
Icons.add_to_queue,
color: Colors.white,
size: _iconSizeAnimation.value,
),
),
onTap: _addAdvFct,
)
And here is my method:
void _addAdvFct() {
print(_advFctPompaList.length);
_advFctPompaList.add(
AdvFctPompa(
name: 'Bloc initial',
temp: '4748425',
imgPath: img2,
constraint: constraints,
),
);
setState(() {});
}
I also tried:
void _addAdvFct() {
print(_advFctPompaList.length);
setState(() {
_advFctPompaList.add(
AdvFctPompa(
name: 'Bloc initial',
temp: '4748425',
imgPath: img2,
constraint: constraints,
),
);
});
}
And the way I want to draw my list is through a LayoutBuider:
Expanded(
child: LayoutBuilder(builder: (_, constraint) {
_initConstrains(constraint);
return ListView(
padding: const EdgeInsets.only(right: 20),
scrollDirection: Axis.horizontal,
children: _advFctPompaList,
);
}),
),
The thing is that when I press the button it show me in console that the number of list elements is increasing, but nothing is changing on the screen.
Am I missing something?
Try
void _addAdvFct() {
print(_advFctPompaList.length);
_advFctPompaList.add(
AdvFctPompa(
name: 'Bloc initial',
temp: '4748425',
imgPath: img2,
constraint: constraints,
),
);
setState(() {
_advFctPompaList;
});
}

Flutter hero transaction container with conditional widgets

I'm trying to implement a hero transaction which is going smoothly, but the container that I'm transitioning has two variants (small/big).
Big:
Small:
As you can see is the small version the same as the big one, but just with some elements missing. The version that needs to be rendered is set with a property isSmall.
The component looks as followed:
class TicPackage extends StatelessWidget {
TicPackage({this.package, this.onTap, this.isSmall = false});
final Package package;
final bool isSmall;
final Function() onTap;
final NumberFormat currencyFormatter =
NumberFormat.currency(locale: "nl", decimalDigits: 2, symbol: "€");
#override
Widget build(BuildContext context) {
Widget titleText = Text(
package.name,
style: TextStyle(
color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold),
);
return TicCard(
color: package.color,
elevation: 4,
onTap: onTap,
children: <Widget>[
Row(
children: <Widget>[
isSmall
? titleText
: Text("${package.eventCount} evenementen",
style:
TextStyle(color: Color.fromRGBO(255, 255, 255, 0.5))),
Text(
"${currencyFormatter.format(package.price)}",
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold),
),
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
),
if (!isSmall)
Padding(padding: EdgeInsets.only(top: 10), child: titleText),
Padding(
padding: EdgeInsets.only(top: 2),
child: Text(package.description,
style: TextStyle(color: Colors.white))),
if (!isSmall)
Padding(
padding: EdgeInsets.only(top: 12),
child: Text(package.goods,
style: TextStyle(
color: Colors.white, fontStyle: FontStyle.italic))),
if (!isSmall)
Padding(
padding: EdgeInsets.only(top: 10),
child: Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 3),
child: Text(
"${currencyFormatter.format(package.discount)} korting",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
border:
Border.all(color: Color.fromRGBO(255, 255, 255, 0.5)),
borderRadius: BorderRadius.circular(100)),
))
],
);
}
}
Screen A:
Hero(
tag: "package_${args.package.id}",
child: TicPackage(
isSmall: false,
package: args.package
)))
Screen B:
Hero(
tag: "package_${args.package.id}",
child: TicPackage(
isSmall: true,
package: args.package
)))
Now the transition looks as followed:
As you can see it's working quite well, but it's a little bit snappy since I'm using conditional rendering here. Also the back transition gives an error:
A RenderFlex overflowed by 96 pixels on the bottom.
I guess this is because on the way back the space suddenly overflows because those extra widgets are getting rendered.
Now my question is how to properly create a hero component that needs to transition with conditional elements. Or if a hero widget isn't suited for this how can I achieve the same result with doing some custom animations?
Wrap your Column inside TicCard with SingleChildScrollView
import 'package:flutter/material.dart';
import 'page2.dart';
class TicCard extends StatelessWidget {
final List<Widget> children;
final double elevation;
final Color color;
const TicCard({
Key key,
this.children,
this.elevation,
this.color,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => Page2(),
),
),
child: Card(
elevation: elevation,
color: color,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: children,
),
),
),
),
);
}
}
Make use of the flightShuttleBuilder. Within this builder create a new TicCard that takes the hero animation. You can use this animation now to animate all views during flight (screen transition).
One thing that I'm not comfortable with is the _animationWidget. What it does: it wraps all the Widgets inside an FadeTransition and SizeTransition, if there is no animation and isSmall is true it returns an empty Container.
The widget:
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:intl/intl.dart';
import 'package:ticketapp_pakket/components/tic-card.dart';
import 'package:ticketapp_pakket/models/package.dart';
class TicPackage extends StatelessWidget {
TicPackage(
{this.heroTag,
this.package,
this.onTap,
this.isSmall = false,
this.animation});
final String heroTag;
final Animation<double> animation;
final Package package;
final bool isSmall;
final Function() onTap;
final NumberFormat currencyFormatter =
NumberFormat.currency(locale: "nl", decimalDigits: 2, symbol: "€");
Widget _animationWidget({Widget child}) {
return animation != null
? FadeTransition(
opacity: animation,
child: SizeTransition(
axisAlignment: 1.0, sizeFactor: animation, child: child))
: !isSmall ? child : Container();
}
#override
Widget build(BuildContext context) {
Widget eventCountText = _animationWidget(
child: Padding(
padding: EdgeInsets.only(bottom: 10),
child: Text("${package.eventCount} evenementen",
style: TextStyle(color: Color.fromRGBO(255, 255, 255, 0.5)))));
Widget goodsText = _animationWidget(
child: Padding(
padding: EdgeInsets.only(top: 12),
child: Text(package.goods,
style:
TextStyle(color: Colors.white, fontStyle: FontStyle.italic))),
);
Widget discountText = _animationWidget(
child: Padding(
padding: EdgeInsets.only(top: 10),
child: Container(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 3),
child: Text(
"${currencyFormatter.format(package.discount)} korting",
style: TextStyle(color: Colors.white),
)),
decoration: BoxDecoration(
border: Border.all(color: Color.fromRGBO(255, 255, 255, 0.5)),
borderRadius: BorderRadius.circular(100)),
)));
Widget titleText = Text(
package.name,
style: TextStyle(
color: Colors.white, fontSize: 22, fontWeight: FontWeight.bold),
);
Widget card = TicCard(
color: package.color,
borderRadius: BorderRadius.circular(10),
margin: EdgeInsets.only(left: 20, right: 20, bottom: 10, top: 5),
onTap: onTap,
child: Container(
padding: EdgeInsets.all(15),
child: Stack(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
eventCountText,
titleText,
Padding(
padding: EdgeInsets.only(top: 2),
child: Text(package.description,
style: TextStyle(color: Colors.white))),
goodsText,
discountText,
],
),
Positioned(
child: Text(
"${currencyFormatter.format(package.price)}",
style: TextStyle(
color: Colors.white,
fontSize: 22,
fontWeight: FontWeight.bold),
),
top: 0,
right: 0)
],
),
));
if (heroTag == null) {
return card;
}
return Hero(
tag: heroTag,
flightShuttleBuilder: (
BuildContext flightContext,
Animation<double> animation,
HeroFlightDirection flightDirection,
BuildContext fromHeroContext,
BuildContext toHeroContext,
) {
return TicPackage(
package: package,
animation: ReverseAnimation(animation),
);
},
child: card);
}
}
How to use the widget:
Use the TicPackage widget on both screens and use the same heroTag.
TicPackage(
heroTag: "package_1",
package: package,
onTap: () {
Navigator.pushNamed(context, '/package-detail',
arguments: PackageDetailPageArguments(package: package));
})
Result:
Result in slow motion:

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