Flutter Zoom out effect on Stack of cards by swipe down - animation

I am trying to implement swipe down on stack of cards and making them zoom out.
I have tried many basic animations together but nothing worked.
Here is one of my code that i have tried:
class _HomePageState extends State<HomePage> {
final HomeController _controller;
double _scaley = 1;
double skewY = 0;
double rotateZ = 0;
double radius = 15.0;
_HomePageState(this._controller);
#override
void initState() {
super.initState();
refreshView();
}
refreshView() {
_controller.init((result) {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return _controller.isLoading
? Center(
child: CircularProgressIndicator(),
)
: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
_controller.data.defaultCard == null
? Container()
: Container(
height: MediaQuery.of(context).size.height / 2.4,
child: new GestureDetector(
onVerticalDragDown: (DragDownDetails details) {
skewY = 0.3;
rotateZ = -3.14 / 18.0;
_scaley = 1.1;
radius = 20.0;
setState(() {});
},
child: Stack(
alignment: FractionalOffset.topRight,
children: <Widget>[
Positioned(
top: 20,
child: Transform(
transform: Matrix4.skewX(skewY)..rotateZ(rotateZ)..scale(_scaley),
child: OtherCard(
radius: radius,
card: _controller.data.defaultCard,
defaultCard: true,
callback: refreshView,
),
),
),
Positioned(
top: 70,
child: Transform(
transform: Matrix4.skewX(skewY)..rotateZ(rotateZ)..scale(_scaley),
child: OtherCard(
radius: radius,
card: _controller.data.defaultCard,
defaultCard: true,
callback: refreshView,
),
),
),
Positioned(
top: 120,
child: Transform(
transform: Matrix4.skewX(skewY)..rotateZ(rotateZ)..scale(_scaley),
child: OtherCard(
radius: radius,
card: _controller.data.defaultCard,
defaultCard: true,
callback: refreshView,
),
),
),
],
),
),
),
],
),
);
}
}
I need animation like Apple pay:
Its showing single card and I need to show 3 cards as stack:
and by dragging them down will zoom them out(like gif)

Related

How to put a var instead of a string in Email Validation package

I need to put a var in the string place in email validator:
var email;
void validation(){
bool emailvalidated = EmailValidator.validate(email);
if (emailvalidated) {
print('object');
}
}
but it throw me this error :
Invalid arguments: email.
Help!!
You are getting the error because the validate method needs a string.
Replace your code with the one below:
It works perfectly well:
// change your email variable to a have a default string
var email = 'youremail.com';
void validation(){
bool emailvalidated = EmailValidator.validate(email);
if (emailvalidated) {
print('object');
}
}
I hope it helps.
UPDATED
Add the variables below to your class:
// define a controller to assign to your custom text field
TextEditingController emailEditingController = TextEditingController();
// declare the email variable here
String email;
Replace your emailTextFormField widget with the one below:
Widget emailTextFormField() {
return CustomTextField(
// assign your email controller to the custom text field here
textEditingController: emailEditingController,
keyboardType: TextInputType.emailAddress,
icon: Icons.email,
hint: "Email ID",
textEditingController: email,
);
}
Replace this with your validation function
void validation() {
// email should be instantiated here
email = emailEditingController.text;
bool emailvalidated = EmailValidator.validate(email);
if (emailvalidated) {
print('Email validated');
} else{
print('email not validated');
}
}
I hope this helps.
import 'package:flutter/material.dart';
import 'package:login_signup/constants/constants.dart';
import 'package:login_signup/ui/widgets/custom_shape.dart';
import 'package:login_signup/ui/widgets/customappbar.dart';
import 'package:login_signup/ui/widgets/responsive_ui.dart';
import 'package:login_signup/ui/widgets/textformfield.dart';
import 'package:email_validator/email_validator.dart';
class SignUpScreen extends StatefulWidget {
#override
_SignUpScreenState createState() => _SignUpScreenState();
}
class _SignUpScreenState extends State<SignUpScreen> {
bool checkBoxValue = false;
double _height;
double _width;
double _pixelRatio;
bool _large;
bool _medium;
var email;
void validation(var val) {
bool emailvalidated = EmailValidator.validate(val);
if (emailvalidated) {
print('object');
}
}
#override
Widget build(BuildContext context) {
_height = MediaQuery.of(context).size.height;
_width = MediaQuery.of(context).size.width;
_pixelRatio = MediaQuery.of(context).devicePixelRatio;
_large = ResponsiveWidget.isScreenLarge(_width, _pixelRatio);
_medium = ResponsiveWidget.isScreenMedium(_width, _pixelRatio);
return Material(
child: Scaffold(
body: Container(
height: _height,
width: _width,
margin: EdgeInsets.only(bottom: 5),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Opacity(opacity: 0.88, child: CustomAppBar()),
clipShape(),
form(),
acceptTermsTextRow(),
SizedBox(
height: _height / 35,
),
button(),
infoTextRow(),
socialIconsRow(),
//signInTextRow(),
],
),
),
),
),
);
}
Widget clipShape() {
return Stack(
children: <Widget>[
Opacity(
opacity: 0.75,
child: ClipPath(
clipper: CustomShapeClipper(),
child: Container(
height: _large
? _height / 8
: (_medium ? _height / 7 : _height / 6.5),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.orange[200], Colors.pinkAccent],
),
),
),
),
),
Opacity(
opacity: 0.5,
child: ClipPath(
clipper: CustomShapeClipper2(),
child: Container(
height: _large
? _height / 12
: (_medium ? _height / 11 : _height / 10),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.orange[200], Colors.pinkAccent],
),
),
),
),
),
Container(
height: _height / 5.5,
alignment: Alignment.center,
decoration: BoxDecoration(
boxShadow: [
BoxShadow(
spreadRadius: 0.0,
color: Colors.black26,
offset: Offset(1.0, 10.0),
blurRadius: 20.0),
],
color: Colors.white,
shape: BoxShape.circle,
),
child: GestureDetector(
onTap: () {
print('Adding photo');
},
child: Icon(
Icons.add_a_photo,
size: _large ? 40 : (_medium ? 33 : 31),
color: Colors.orange[200],
)),
),
// Positioned(
// top: _height/8,
// left: _width/1.75,
// child: Container(
// alignment: Alignment.center,
// height: _height/23,
// padding: EdgeInsets.all(5),
// decoration: BoxDecoration(
// shape: BoxShape.circle,
// color: Colors.orange[100],
// ),
// child: GestureDetector(
// onTap: (){
// print('Adding photo');
// },
// child: Icon(Icons.add_a_photo, size: _large? 22: (_medium? 15: 13),)),
// ),
// ),
],
);
}
Widget form() {
return Container(
margin: EdgeInsets.only(
left: _width / 12.0, right: _width / 12.0, top: _height / 20.0),
child: Form(
child: Column(
children: <Widget>[
firstNameTextFormField(),
SizedBox(height: _height / 60.0),
lastNameTextFormField(),
SizedBox(height: _height / 60.0),
emailTextFormField(),
SizedBox(height: _height / 60.0),
phoneTextFormField(),
SizedBox(height: _height / 60.0),
passwordTextFormField(),
],
),
),
);
}
Widget firstNameTextFormField() {
return CustomTextField(
keyboardType: TextInputType.text,
icon: Icons.person,
hint: "First Name",
);
}
Widget lastNameTextFormField() {
return CustomTextField(
keyboardType: TextInputType.text,
icon: Icons.person,
hint: "Last Name",
);
}
Widget emailTextFormField() {
return CustomTextField(
keyboardType: TextInputType.emailAddress,
icon: Icons.email,
hint: "Email ID",
textEditingController: email,
);
}
Widget phoneTextFormField() {
return CustomTextField(
keyboardType: TextInputType.number,
icon: Icons.phone,
hint: "Mobile Number",
);
}
Widget passwordTextFormField() {
return CustomTextField(
keyboardType: TextInputType.text,
obscureText: true,
icon: Icons.lock,
hint: "Password",
);
}
Widget acceptTermsTextRow() {
return Container(
margin: EdgeInsets.only(top: _height / 100.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Checkbox(
activeColor: Colors.orange[200],
value: checkBoxValue,
onChanged: (bool newValue) {
setState(() {
checkBoxValue = newValue;
});
}),
Text(
"I accept all terms and conditions",
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: _large ? 12 : (_medium ? 11 : 10)),
),
],
),
);
}
Widget button() {
return RaisedButton(
elevation: 0,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(30.0)),
onPressed: () {
validation(email);
},
textColor: Colors.white,
padding: EdgeInsets.all(0.0),
child: Container(
alignment: Alignment.center,
// height: _height / 20,
width: _large ? _width / 4 : (_medium ? _width / 3.75 : _width / 3.5),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
gradient: LinearGradient(
colors: <Color>[Colors.orange[200], Colors.pinkAccent],
),
),
padding: const EdgeInsets.all(12.0),
child: Text(
'SIGN UP',
style: TextStyle(fontSize: _large ? 14 : (_medium ? 12 : 10)),
),
),
);
}
Widget infoTextRow() {
return Container(
margin: EdgeInsets.only(top: _height / 40.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Or create using social media",
style: TextStyle(
fontWeight: FontWeight.w400,
fontSize: _large ? 12 : (_medium ? 11 : 10)),
),
],
),
);
}
Widget socialIconsRow() {
return Container(
margin: EdgeInsets.only(top: _height / 80.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
CircleAvatar(
radius: 15,
backgroundImage: AssetImage("assets/images/googlelogo.png"),
),
SizedBox(
width: 20,
),
CircleAvatar(
radius: 15,
backgroundImage: AssetImage("assets/images/fblogo.jpg"),
),
SizedBox(
width: 20,
),
CircleAvatar(
radius: 15,
backgroundImage: AssetImage("assets/images/twitterlogo.jpg"),
),
],
),
);
}
Widget signInTextRow() {
return Container(
margin: EdgeInsets.only(top: _height / 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Already have an account?",
style: TextStyle(fontWeight: FontWeight.w400),
),
SizedBox(
width: 5,
),
GestureDetector(
onTap: () {
Navigator.of(context).pop(SIGN_IN);
print("Routing to Sign up screen");
},
child: Text(
"Sign in",
style: TextStyle(
fontWeight: FontWeight.w800,
color: Colors.orange[200],
fontSize: 19),
),
)
],
),
);
}
}
Here:
import 'package:flutter/material.dart';
import 'package:login_signup/ui/widgets/responsive_ui.dart';
class CustomTextField extends StatelessWidget {
final String hint;
final TextEditingController textEditingController;
final TextInputType keyboardType;
final bool obscureText;
final IconData icon;
double _width;
double _pixelRatio;
bool large;
bool medium;
CustomTextField(
{this.hint,
this.textEditingController,
this.keyboardType,
this.icon,
this.obscureText= false,
});
#override
Widget build(BuildContext context) {
_width = MediaQuery.of(context).size.width;
_pixelRatio = MediaQuery.of(context).devicePixelRatio;
large = ResponsiveWidget.isScreenLarge(_width, _pixelRatio);
medium= ResponsiveWidget.isScreenMedium(_width, _pixelRatio);
return Material(
borderRadius: BorderRadius.circular(30.0),
elevation: large? 12 : (medium? 10 : 8),
child: TextFormField(
controller: textEditingController,
keyboardType: keyboardType,
cursorColor: Colors.orange[200],
decoration: InputDecoration(
prefixIcon: Icon(icon, color: Colors.orange[200], size: 20),
hintText: hint,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(30.0),
borderSide: BorderSide.none),
),
),
);
}
}

Animate multiple widgets on same screen flutter

I need slide animation from left to right and vice versa.
Can anyone give me any guidance which widget i should use in it?
I have tried a few thing like :- carousel_slider, transformer_pageview, page_transformer
I used SlideTransition class, but it is not giving me expected result, I have also tried different range/values of OffSet but no luck.
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:sliding_up_panel/sliding_up_panel.dart';
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
AnimationController _controller;
Animation<Offset> _offsetAnimation;
AnimationController _controllerTwo;
Animation<Offset> _offsetAnimationTwo;
#override
void initState() {
_controller = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_offsetAnimation = Tween<Offset>(
begin: const Offset(-0.00001, 0.0),
end: const Offset(0.09, 0.0),
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.easeInOut,
));
_controllerTwo = AnimationController(
duration: const Duration(seconds: 1),
vsync: this,
);
_offsetAnimationTwo = Tween<Offset>(
begin: const Offset(-0.85, 0.0),
end: const Offset(-0.00001, 0.0),
).animate(CurvedAnimation(
parent: _controllerTwo,
curve: Curves.easeInOut,
));
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Expanded(
child: new GestureDetector(
onHorizontalDragUpdate: (details) {
if (details.primaryDelta > 0) {
_controller..reverse();
_controllerTwo..reverse();
}
if (details.primaryDelta < 0) {
_controller..forward();
_controllerTwo..forward();
}
print(details.primaryDelta);
},
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
SlideTransition(
position: _offsetAnimationTwo,
child: Card(
color: Colors.black54,
child: Container(),
),
),
Flexible(
child: SlideTransition(
position: _offsetAnimation,
child: Container(
child: SlidingUpPanel(
renderPanelSheet: false,
panel: _floatingStatement(),
body: CardsStack(context),
),
),
),
),
],
),
),
)
],
);
}
Widget _floatingStatement() {
return Container(
margin: const EdgeInsets.all(24.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(24.0)),
boxShadow: [
BoxShadow(
blurRadius: 20.0,
color: Colors.grey,
),
],
),
);
}
}
class CardsStack extends StatelessWidget {
const CardsStack(BuildContext context, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return new Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
top: 20,
left: 10,
right: 10,
child: Card(
color: Colors.black54,
child: Container(),
),
),
Positioned(
top: 70,
left: 10,
right: 10,
child: Card(
color: Colors.black54,
child: Container(),
),
),
Positioned(
top: 120,
left: 10,
right: 10,
child: Card(
color: Colors.black54,
child: Container(),
),
),
],
);
}
}
You can use PageView to horizontally (even vertically) swipe between pages.
Or you can use TabBarView to implement it with bottom navigation.
Example code:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class HomePage extends StatelessWidget {
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: 3,
child: Scaffold(
body: TabBarView(
children: <Widget>[
Center(child: Text("Page1")),
Center(child: Text("Page2")),
Center(child: Text("Page3")),
],
),
bottomNavigationBar: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10.0),
topRight: Radius.circular(10.0),
),
boxShadow: [
BoxShadow(
color: Colors.black,
offset: Offset(0, 0),
blurRadius: 10.0,
),
],
),
child: TabBar(
indicatorColor: Colors.red,
indicatorWeight: 5.0,
indicatorSize: TabBarIndicatorSize.label,
labelColor: Colors.black,
tabs: <Widget>[
Tab(icon: Icon(Icons.home)),
Tab(icon: Icon(Icons.category)),
Tab(icon: Icon(Icons.account_circle)),
],
),
),
),
);
}
}

How to make my Flutter app generate numbers only when it is needed?

So the idea of my program is to generate random numbers with operators and then make a non-for-user result of this operation. And it works, but my app refreshes the data every time I make any action like opening TextField or submitting the result to compare user input with an actual answer.
I guess the problem is because of bad State managment but I cant figure out how to fix it myself.
(I have my own Mathematics class with functions for program but where is no need to worry about)
The code what`s required:
class _GameplayPageState extends State<GameplayPage> {
#override
Widget build(BuildContext context) {
var mathManager = Mathematics();
var firstNum = mathManager.getNumber();
var secondNum = mathManager.getNumber();
var mathOperator = mathManager.getOperator();
var calResult = mathManager.calculate(firstNum, mathOperator, secondNum);
Positioned(
top: 120,
child: Container(
width: screenWidth,
height: 230,
// decoration: BoxDecoration(color: Colors.orange),
child: Align(
alignment: Alignment.center,
child: Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(
width: 10,
),
// >>>> LOOK HERE
Text(
firstNum.toString(),
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5),
),
Text(
mathOperator,
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 70,
color: Color(0xff52de97),
),
),
Text(
secondNum.toString(),
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5,
),
),
SizedBox(
width: 10,
),
],
),
),
),
),
),
child: TextField(
onSubmitted: (String value) async {
await showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
content: (value == calResult ? Text('Right') : Text('Wrong!')),
);
});
},
FlatButton(
onPressed: () {
setState(() {
});
},
Sorry for bad formatting ;(
I am not sure with what you are trying to achieve but here's simple code you can try which don't generate new number after checking if the input correct or not and also has new generate number button
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: Pageone(),
),
);
}
}
class Pageone extends StatefulWidget {
#override
_PageoneState createState() => _PageoneState();
}
class _PageoneState extends State<Pageone> {
TextEditingController controller = TextEditingController();
int a = Random().nextInt(10);
int b = Random().nextInt(10);
int c;
String result;
#override
void initState() {
plus();
super.initState();
}
void plus() {
c = a + b;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
SizedBox(
width: 10,
),
Text(
'$a',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5),
),
Text(
'$b',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
),
),
Text(
'$c',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5,
),
),
SizedBox(
width: 10,
),
],
),
Form(
child: Column(
children: <Widget>[
Container(
width: 300,
child: TextFormField(
controller: controller,
onFieldSubmitted: (String value) {
setState(() =>
result = int.parse(value) == c ? 'true' : 'false');
},
),
),
],
),
),
Text(
result == null ? '' : '$result',
style: TextStyle(
fontFamily: 'Montserrat',
fontSize: 100,
color: Color(0xff52de97),
letterSpacing: 0.5),
),
MaterialButton(
child: Text('Generate new'),
onPressed: () {
setState(() {
a = Random().nextInt(10);
b = Random().nextInt(10);
plus();
});
},
),
],
),
);
}
}
You can try creating a separate stateful widget to contain the part of code where the setstate() is called and convert the original widget to a stateless one.
In your code, the GameplayPage widget rebuilds itself whenever any value is updated. This is because the setstate() causes the widget to rebuild. So you should separate the things that don't change and those that change into different widgets.
For example, you can create the FlatButton as a custom widget and sent the necessary details as parameters.
So I solved this problem via making my mathematics object into several functions and then doing the hardest work before Widget build. The code:
var b = (Random().nextInt(99) + 1);
var operate = getOperator();
var result;
#override
void initState(){
result = calculate(a,operate,b);
super.initState();
}
Thanks everyone for contributing!

Flutter animation

How can I fade out 1st widget, and animate 2nd widget to come from bottom, and replace the 1st widget, once user click the button?
And on click on second button, to make 2nd widget go down and 1st widget fade in?
You can do that with an AnimatedOpacity for the first widget and an AnimatedPositioned for the second one. Here you have an example:
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
double _firstWidgetOpacity = 1.0;
double _secondWidgetBottomPosition = -200.0;
animate() {
setState(() {
if (_firstWidgetOpacity == 1.0) {
_firstWidgetOpacity = 0.0;
_secondWidgetBottomPosition = MediaQuery.of(context).size.height / 2 - 140.0;
} else {
_firstWidgetOpacity = 1.0;
_secondWidgetBottomPosition = -200.0;
}
});
}
#override
void initState() {
super.initState();
print((560 / 60).floor());
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: animate,
label: Text('Animate'),
),
body: Stack(
children: <Widget>[
Align(
alignment: Alignment.center,
child: AnimatedOpacity(
duration: Duration(milliseconds: 350),
opacity: _firstWidgetOpacity,
curve: Curves.easeIn,
child: Container(
width: 200.0,
height: 200.0,
color: Colors.blue,
child: Center(
child: Text('First widget'),
),
),
),
),
AnimatedPositioned(
duration: Duration(milliseconds: 350),
curve: Curves.elasticIn,
bottom: _secondWidgetBottomPosition,
left: 0.0,
right: 0.0,
child: Center(
child: Container(
width: 200.0,
height: 200.0,
color: Colors.orange,
child: Center(
child: Text('Second widget'),
),
),
),
),
],
),
);
}
}
You can play with the durations and curves to get the result that you need.

Flutter: Notifications UI

I can't distinguish new Firebase Cloud Messaging notifications from older ones in my Flutter UI. How can I fix this? Thanks.
EXAMPLE: 3 users comment on an author's post that already has 2 "seen" comments. The author's post gets a +3 red marble on it. When the author clicks on this post in the Notifications tab, the user is routed to its comments, that +3 reduces to 0, and the bottom tab marble reduces to 3 (6-3=3) as well.
Dummy UI Code and Pics below.
1. A blank "home page;"
2. a dummy notifications page with posts that have been replied to
3. On clicking a post, a comments page.
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
"/comment": (BuildContext context) => new commentFoundation(),
},
home: MainScreen());
}
}
//The content of the notification tab.
class Notification extends StatefulWidget {
#override
_NotificationState createState() => new _NotificationState();
}
class _NotificationState extends State<Notification> {
#override
Widget build(BuildContext context) {
return _buildPostList();
}
Widget _buildPostList() {
return new Scaffold(
backgroundColor: Colors.blue,
body: new Scrollbar(
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return new Container(
child: new Stack(children: <Widget>[
new Column(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 0.0, left: 12.0),
child: DummyPost()),
],
),
replyNotification(),
]));
},
itemCount: 2,
)));
}
Widget replyNotification() {
return new Positioned(
left: 175,
top: 205.5,
child: new Container(
padding: EdgeInsets.only(left: 3.0, right: 3.0),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(30),
),
constraints: BoxConstraints(
minWidth: 30,
minHeight: 30,
),
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.only(top: 0.0),
child: new Text(
'+',
style: new TextStyle(
color: Colors.white,
fontSize: 26,
),
textAlign: TextAlign.center,
)),
Container(
padding: EdgeInsets.only(right: 0.0),
child: new Text(
'3',
style: new TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold,
),
textAlign: TextAlign.center,
)),
],
)),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => new _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Center(
child: new Container(
child: Text("HomePageStuff"),
));
}
}
//A dummy post in notififications tab
class DummyPost extends StatefulWidget {
#override
_DummyPostState createState() => new _DummyPostState();
}
class _DummyPostState extends State<DummyPost> {
bool monVal = false;
bool reportPressed = false;
Widget commentButton() {
return RaisedButton(
child: Text("ReplyButton"),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => commentFoundation())),
);
}
#override
Widget build(BuildContext context) {
return postList();
}
Widget postList() {
return Column(children: <Widget>[
new GestureDetector(
//this type works
onTap: () => Navigator.pushNamed(context, '/comment'),
child: new Stack(children: <Widget>[
Column(children: <Widget>[
SizedBox(
height: 10.0,
),
Container(
margin: EdgeInsets.only(top: 35.0),
width: 390.0,
child: Card(
shape: RoundedRectangleBorder(
//15?
borderRadius: BorderRadius.circular(5.0),
),
color: Colors.white,
elevation: 2.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new Flexible(
child: ListTile(
// The main post content
subtitle: Container(
height: 130.0,
margin: EdgeInsets.only(
top: 15.0, left: 15.0, right: 15.0),
child: Container(
child: Center(
child: Text(
"This is a dummy post",
textAlign: TextAlign.center,
style: TextStyle(
wordSpacing: 3.0,
color: Colors.black,
fontSize: 18.0),
))),
),
)),
//button row
new Container(
width: 400.0,
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
margin: EdgeInsets.only(right: 0.0),
width: 190.0,
height: 40.0,
child: commentButton(),
),
// Text to indicate comment numbers
],
)),
],
))),
]),
]))
]);
}
}
//the entire comment page.
class commentFoundation extends StatefulWidget {
#override
_commentFoundationState createState() => new _commentFoundationState();
}
class _commentFoundationState extends State<commentFoundation> {
ScrollController _scrollController = new ScrollController();
#override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.green,
appBar: _buildAppBar(),
body: new Stack(children: <Widget>[
ListView.builder(
shrinkWrap: true,
controller: _scrollController,
itemCount: 5,
itemBuilder: (BuildContext context, int index) {
return new individualComment();
}),
]));
}
Widget _buildAppBar() {
return AppBar(
title: Text("REPLIES"),
automaticallyImplyLeading: true,
backgroundColor: Colors.white,
elevation: 0.0,
);
}
}
//Each individual comment you see when you click on a post
class individualComment extends StatefulWidget {
final String title;
const individualComment({Key key, this.title}) : super(key: key);
#override
_individualCommentState createState() => new _individualCommentState();
}
class _individualCommentState extends State<individualComment> {
#override
Widget build(BuildContext context) {
return new Stack(
children: <Widget>[
Column(children: <Widget>[
//this used to be an expanded
new Container(
child: Card(
elevation: 0.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new ListTile(
// The avatar
leading: Container(
child: Icon(
Icons.accessibility_new,
)),
// Title, location, and time
// The main post content
subtitle: Container(
margin: EdgeInsets.only(top: 10.0, bottom: 0.0),
child: Text(
"This is a reply",
style: TextStyle(
color: Colors.black,
fontSize: .0364609 *
MediaQuery.of(context).size.width),
),
),
),
],
))),
])
],
);
}
}
//*****This is just the tabbar.
class MainScreen extends StatefulWidget {
#override
_MainScreenstate createState() => new _MainScreenstate();
}
class _MainScreenstate extends State<MainScreen> with TickerProviderStateMixin {
String _lastSelected = '0';
final List<Widget> _bodyOptions = [
HomePage(),
Notification(),
];
int _selectedIndex = 0;
bool tab = true;
_selectedTab(int index) {
setState(() {
_lastSelected = '$index';
});
}
Widget __buildTabs() {
return Scaffold(
body: _bodyOptions.elementAt(int.parse(_lastSelected)),
//around the FAB
backgroundColor: const Color(0xFFF4F4F4),
bottomNavigationBar: new Stack(
children: <Widget>[
FABBottomAppBar(
height: 45.0,
centerItemText: '',
color: Colors.black,
selectedColor: Colors.blue,
notchedShape: CircularNotchedRectangle(),
onTabSelected: _selectedTab,
items: [
FABBottomAppBarItem(iconData: Icons.search, text: 'Home'),
FABBottomAppBarItem(
iconData: Icons.notifications, text: 'Notifications'),
],
),
//the red "notification" marble
new Positioned(
right: 20,
top: 0.5,
child: new Container(
padding: EdgeInsets.all(1),
decoration: new BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(12),
),
constraints: BoxConstraints(
minWidth: 20,
minHeight: 20,
),
child: new Text(
'6',
style: new TextStyle(
color: Colors.white,
fontSize: 14,
),
textAlign: TextAlign.center,
),
),
)
],
));
}
#override
Widget build(BuildContext context) {
return __buildTabs();
}
}
//Everything below is boiler plate tabbar code.
class FABBottomAppBarItem {
FABBottomAppBarItem({this.iconData, this.text});
IconData iconData;
String text;
}
class FABBottomAppBar extends StatefulWidget {
FABBottomAppBar({
this.items,
this.centerItemText,
this.height: 60.0,
this.iconSize: 24.0,
this.backgroundColor,
this.color,
this.selectedColor,
this.notchedShape,
this.onTabSelected,
}) {
assert(this.items.length == 2 || this.items.length == 4);
}
final List<FABBottomAppBarItem> items;
final String centerItemText;
final double height;
final double iconSize;
final Color backgroundColor;
final Color color;
final Color selectedColor;
final NotchedShape notchedShape;
final ValueChanged<int> onTabSelected;
#override
State<StatefulWidget> createState() => FABBottomAppBarState();
}
class FABBottomAppBarState extends State<FABBottomAppBar> {
int _selectedIndex = 0;
_updateIndex(int index) {
widget.onTabSelected(index);
setState(() {
_selectedIndex = index;
});
return _selectedIndex;
}
#override
Widget build(BuildContext context) {
List<Widget> items = List.generate(widget.items.length, (int index) {
return _buildTabItem(
item: widget.items[index],
index: index,
onPressed: _updateIndex,
);
});
items.insert(items.length >> 1, _buildMiddleTabItem());
return BottomAppBar(
elevation: 0.0,
notchMargin: 2.0,
shape: CircularNotchedRectangle(),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: items,
),
//color of bottom
color: Colors.white,
);
}
Widget _buildMiddleTabItem() {
return Expanded(
child: SizedBox(
height: widget.height,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SizedBox(height: widget.iconSize),
Text(
widget.centerItemText ?? '',
style: TextStyle(color: widget.color),
),
],
),
),
);
}
Widget _buildTabItem({
FABBottomAppBarItem item,
int index,
ValueChanged<int> onPressed,
}) {
Color color = _selectedIndex == index ? widget.selectedColor : widget.color;
return Expanded(
child: SizedBox(
height: widget.height,
child: Material(
type: MaterialType.transparency,
child: InkWell(
onTap: () => onPressed(index),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(item.iconData, color: color, size: widget.iconSize),
Text(
item.text,
style: TextStyle(color: color),
)
],
),
),
),
),
);
}
}
This seems to be a broad question and I'm unsure if you're asking for suggestions on how you can implement tracking read and unread notifications, or troubleshooting help on your existing code. I suggest checking tips posted on this thread on how you can manage notification counters.

Resources