Related
I am learning Flutter now and i have a screen that loading many series characters, and i have an icon in the AppBar showing
ModalBottomSheet and it have many choices to filter to update data with the new chosen ones.
I got the choices and stored the in a List of Strings but i dont know how to pass it to a function in my cubit file and i don't know how to update data using cubit , i tried many ways but didn't work with me.
Here's my code
import 'package:breakingbad/data/models/breaking_bad_characters.dart';
import 'package:breakingbad/domain/cubit/rick_and_morty_cubit.dart';
import 'package:breakingbad/presentation/character-detail.dart';
import 'package:conditional_builder_null_safety/conditional_builder_null_safety.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../widgets/character_item.dart';
import '../widgets/chip_choice.dart';
class MyHomePage extends StatefulWidget {
static String id ='home';
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return BlocConsumer<RickAndMortyCubit,RickAndMortyState>(
listener: (context, state){},
builder: (context, state) {
var cubit = RickAndMortyCubit.get(context);
return Scaffold(
appBar: AppBar(
title: const Center(child: Text('Rick And Morty')),
actions: [
IconButton(
padding: const EdgeInsets.only(right: 25),
onPressed: (){
showModalBottomSheet(
context: context,
builder: (context) =>
Column(
children: [
Container(
alignment: Alignment.center,
color: Colors.black,
width: double.infinity,
height: 50,
child: const Text('Filter Characters',style: TextStyle(color:
Colors.white,fontSize: 22),),
),
const ChoiceChipWidget(),
],
)
);
},
icon: const Icon(Icons.filter_list_sharp,size: 40,)),
],
),
body: ConditionalBuilder(
condition: state is RickAndMortyCharsLoaded,
fallback: (context)=> const Center(child: CircularProgressIndicator()),
builder: (context) => GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 2 / 3,
crossAxisSpacing: 1,
mainAxisSpacing: 1,
),
itemCount: cubit.allHuman.length,
itemBuilder: (context,index) =>
CharacterItem(
rickAndMortyCharacters: cubit.allHuman[index],
widget:CharacterDetail(rickAndMortyCharacters: cubit.allHuman[index]),
)
),
)
);
}
);
}
}
import 'package:breakingbad/domain/cubit/rick_and_morty_cubit.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ChoiceChipWidget extends StatefulWidget {
const ChoiceChipWidget( {super.key, });
#override
State<ChoiceChipWidget> createState() => _ChoiceChipWidgetState();
}
class _ChoiceChipWidgetState extends State<ChoiceChipWidget> {
String selectedChoice1 = "";
String selectedChoice2 = "";
String selectedChoice3 = "";
List<String> filter=[];
#override
Widget build(BuildContext context) {
return BlocBuilder<RickAndMortyCubit, RickAndMortyState>(
builder: (context, state) {
var cubit = RickAndMortyCubit.get(context);
return Column(
children: [
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Gender',
style: TextStyle(fontSize: 20),
), //Text
),
Row(
children: cubit.gender.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice1 == item,
onSelected: (selected) {
setState(() {
selectedChoice1 = item;
filter.add(selectedChoice1);
});
},
),
);
}).toList()
),
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Species',
style: TextStyle(fontSize: 20),
), //Text
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children:cubit.species.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
fontSize: 18,
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice2 == item,
onSelected: (selected) {
setState(() {
selectedChoice2 = item;
filter.add(selectedChoice2);
});
},
),
);
}).toList()
),
),
Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'Statue',
style: TextStyle(fontSize: 20),
), //Text
),
Row(
children:cubit.statue.map((item){
return Container(
padding: const EdgeInsets.all(2.0),
child: ChoiceChip(
label: Text(item),
labelStyle: const TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(22.0),
),
backgroundColor: Colors.grey[300],
selectedColor: Colors.blue,
selected: selectedChoice3 == item,
onSelected: (selected) {
setState(() {
selectedChoice3 = item;
filter.add(selectedChoice3);
});
},
),
);
}).toList()
),
SizedBox(height: 4,),
InkWell(
onTap: (){
// here i want to apply changes
Navigator.pop(context);
},
child: Chip(
elevation: 20,
padding: const EdgeInsets.all(8),
backgroundColor: Colors.greenAccent[100],
shadowColor: Colors.black,
label: const Text(
'apply',
style: TextStyle(fontSize: 20),
), //Text
),
),
],
);
},
);
}
}
I have two main functions, the first one get all characters to the home screen:
List<Characters>?
getAllCharacters(){
myRepository.
getAllCharacters().then(
(allCharacters)=>
this.allCharacters =
allCharacters;
);
return allCharacters;
}
and the second function that takes a parameter of List of Strings which i suppose to get them from the filtering in bottomSheet;
List<Characters>?
getFilteredCharacters
(List<String> list){
myRepository
.getFilteredCharacters(list)
.then((filteredCharacters)=>
this.filteredCharacters =
filteredCharacters;
);
return filteredCharacters;
}
Anyone could help me in this issue?
I'm building my quiz app and my quizpage is taking solid shape but here's a problem i have. I added a Willpopscope just so that my users can't go back to the beginning when the quiz has started and it brings up a dialog box. Here's the code:
import 'dart:convert';
//import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class GetJson extends StatelessWidget {
const GetJson({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: DefaultAssetBundle.of(context).loadString("assets/python.json"),
builder: (context, snapshot) {
var mydata = jsonDecode(snapshot.data.toString());
if (mydata == null) {
return Scaffold(
body: Center(
child: Text(
"Loading",
),
),
);
} else {
return QuizPage();
}
},
);
}
}
class QuizPage extends StatefulWidget {
QuizPage({Key? key}) : super(key: key);
#override
_QuizPageState createState() => _QuizPageState();
}
class _QuizPageState extends State<QuizPage> {
Widget choicebutton() {
return Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
child: MaterialButton(
onPressed: () {},
child: Text(
"option 1",
style: TextStyle(
color: Colors.white,
fontFamily: "Alike",
fontSize: 16.0,
),
maxLines: 1,
),
color: Colors.indigo,
splashColor: Colors.indigo[700],
highlightColor: Colors.indigo[700],
minWidth: 200.0,
height: 45.0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20.0)),
),
);
}
#override
Widget build(BuildContext context) {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitDown, DeviceOrientation.portraitUp]);
return WillPopScope(
onWillPop: () {
return showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Quizstar",
),
content: Text("You Can't Go Back At This Stage"),
actions: [
// ignore: deprecated_member_use
FlatButton(onPressed: () {
Navigator.of(context).pop();
},
child: Text(
"Ok",
),
)
],
)
);
},
child: Scaffold(
body: Column(
children: [
Expanded(
flex: 3,
child: Container(
padding: EdgeInsets.all(15.0),
alignment: Alignment.bottomLeft,
child: Text(
"This is a sample question which will be displayed?",
style: TextStyle(
fontSize: 16.0,
fontFamily: "Quando",
),
),
),
),
Expanded(
flex: 6,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
choicebutton(),
choicebutton(),
choicebutton(),
choicebutton(),
],
),
),
),
Expanded(
flex: 1,
child: Container(
alignment: Alignment.topCenter,
child: Center(
child: Text(
"30",
style: TextStyle(
fontSize: 35.0,
fontWeight: FontWeight.w700,
fontFamily: "Times New Roman",
),
),
),
),
),
],
),
),
);
}
}
The error is in the showDialog() but i can't seem to figure it out.
Thanks a lot guys.
This might help
On your willpop scope function do this instead
onWillPop: () {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text(
"Quizstar",
),
content: Text("You Can't Go Back At This Stage"),
actions: [
// ignore: deprecated_member_use
FlatButton(onPressed: () {
Navigator.of(context).pop();
},
child: Text(
"Ok",
),
)
],
)
);
return true;
),
child : your widget
Okay i figured it out
return WillPopScope(
onWillPop: () async {
print("Back Button Pressed");
final shouldPop = await showWarning(context);
return shouldPop ?? false;
},
Then i went ahead to define showWarning like this, then defined my dialog box inside it:
Future<bool?> showWarning(BuildContext context) async => showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text("Quizstar"),
content: Text("You cannot go back at this stage"),
actions: [
ElevatedButton(
onPressed: () => Navigator.pop(context, false),
child: Text("Okay"),
),
//ElevatedButton(
// onPressed: () => Navigator.pop(context, true),
// child: Text("Yes"),
//),
],
),
);
Tips: Don't forget to make the future a bool by writing inside it with it's '?'
I already have a bottom navigation bar which navigates to different pages.
then I add a drawer which I want it to change the widget in the body only, but the issue is that I made the drawer in another page and I called it, so it is not responding or I'm not calling it perfectly as I should.
Below is the navigation for the bottomnavigationbar, I have imported all necessary files
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int currentTab = 0;
final tabs = [
IndexPage(),
Save(),
Invest(),
Wallet(),
Cards(),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.grey[900],
debugShowCheckedModeBanner: false,
title: 'Flochristos App',
theme: ThemeData(),
home: Scaffold(
backgroundColor: Colors.black,
resizeToAvoidBottomPadding: false,
resizeToAvoidBottomInset: false,
key: _scaffoldKey,
appBar: AppBar(
backgroundColor: Colors.grey[900],
title: Text(
'PettySave',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.brightness_7_outlined),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.keyboard_arrow_down_sharp),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.account_circle_rounded),
onPressed: () {},
),
],
//shadowColor: Colors.grey,
),
body: tabs[currentTab], //this is where I want to change the pages
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
bottomNavigationBar: BottomNavigationBar(
onTap: (int index) {
setState(() {
currentTab = index;
});
},
currentIndex: currentTab,
backgroundColor: Colors.grey[900],
unselectedIconTheme: IconThemeData(color: Colors.grey),
selectedItemColor: Colors.green,
unselectedItemColor: Colors.grey,
type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home_filled),
// ignore: deprecated_member_use
title: Text(
"Home",
),
),
BottomNavigationBarItem(
icon: FaIcon(FontAwesomeIcons.pagelines),
// ignore: deprecated_member_use
title: Text(
"Save",
),
),
BottomNavigationBarItem(
icon: Icon(Icons.trending_up),
// ignore: deprecated_member_use
title: Text(
"Invest",
),
),
BottomNavigationBarItem(
icon: Icon(Icons.account_balance_wallet_outlined),
// ignore: deprecated_member_use
title: Text(
"Wallet",
),
),
BottomNavigationBarItem(
icon: Icon(Icons.credit_card),
// ignore: deprecated_member_use
title: Text(
"Cards",
),
),
],
),
),
);
}
}
}
that's the main.dart code
body: tabs[currentTab], //this is where I want to change the pages
then I created another page for drawer which I called all appropriate pages
from one of the list style in the slidedrawer.dart , I'm trying to set currentTab to any index I want.... but it's not working.
ListTile(
contentPadding: EdgeInsets.fromLTRB(30, 0, 0, 0),
leading: Icon(
Icons.trending_up,
color: Colors.grey[500],
),
title: Text(
'Investments',
style: TextStyle(
color: Colors.grey[300],
fontWeight: FontWeight.bold,
),
),
onTap: () {
setState(() {
currentTab = 1;
});
},
),
I want the index to turn to Save()
List<Widget> tabs = [
IndexPage(),
Save(),
Invest(),
Wallet(),
Cards(),
];
There are many ways to add a drawer to an app, but the most common one is to use the drawer property thats within the Scaffold() Widget.
e.x.
Scaffold(
appBar: AppBar(
...
),
drawer: Drawer() // This is where you call the new Widget(class) that you made the drawer in
body: tabs[currentTab],
);
This is how I understood your question, correct me if I misunderstood it.
This is an example how I used a navigation tab bar in one of my projects.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../providers/auth.dart';
import '../../../widgets/auth/admin/main_drawer.dart';
import '../../auth/profile_screen.dart';
import '../../home_screen.dart';
import './../projects_screen.dart';
class AdminTabBarScreen extends StatefulWidget {
static const routeName = 'auth-tab-bar-view';
#override
_AdminTabBarScreenState createState() => _AdminTabBarScreenState();
}
class _AdminTabBarScreenState extends State<AdminTabBarScreen>
with SingleTickerProviderStateMixin {
TabController _tabController;
#override
void initState() {
_tabController = TabController(length: 3, vsync: this);
super.initState();
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final auth = Provider.of<Auth>(context);
return Scaffold(
// appBar: AppBar(
// title: Text('SHTEGU'),
// ),
extendBody: true,
drawer: MainDrawer(), // this is where I called my drawer
body: Container(
// color: Colors.blueAccent,
child: TabBarView(
children: <Widget>[
HomeScreen(),
ProjectsScreen(),
ProfileScreen(),
// LoginScreen(),
],
controller: _tabController,
),
),
bottomNavigationBar: Container(
padding: EdgeInsets.all(16.0),
child: ClipRRect(
borderRadius: BorderRadius.all(
Radius.circular(50.0),
),
child: Container(
color: Colors.black26,
child: TabBar(
labelColor: Color(0xFFC41A3B),
unselectedLabelColor: Colors.white,
labelStyle: TextStyle(fontSize: 13.0),
indicator: UnderlineTabIndicator(
borderSide: BorderSide(color: Colors.black54, width: 0.0),
insets: EdgeInsets.fromLTRB(50.0, 0.0, 50.0, 40.0),
),
//For Indicator Show and Customization
indicatorColor: Colors.black54,
tabs: <Widget>[
Tab(
text: 'Home',
),
Tab(
text: 'Projects',
),
Tab(
text: 'Profile',
),
// Tab(
// text: 'Login',
// ),
],
controller: _tabController,
),
),
),
),
);
}
}
Here is how I called the class above to check if admin
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../screens/auth/admin/admin_tab_bar_screen.dart';
import '../../screens/auth/user_tab_bar_screen.dart';
import '../../providers/auth.dart';
class AuthTabBarScreen extends StatelessWidget {
static const routeName = 'auth-tab-bar-view';
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: Provider.of<Auth>(context, listen: false).isAdmin(),
builder: (context, snapshot) => snapshot.hasData
? snapshot.data
? AdminTabBarScreen()
: UserTabBarScreen()
: CircularProgressIndicator(), // while you're waiting for the data, show some kind of loading indicator
);
}
}
And here is my drawer:
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../../screens/auth/admin/register_user_screen.dart';
import '../../../screens/auth/auth_tab_bar_screen.dart';
import '../../../screens/tab_bar_screen.dart';
import '../../../providers/auth.dart';
class MainDrawer extends StatelessWidget {
Widget buildListTile(
String title, IconData icon, Function tapHandler, BuildContext ctx) {
return ListTile(
tileColor: Color(0xffF2F7FB),
selectedTileColor: Theme.of(ctx).accentColor,
leading: Icon(
icon,
size: 26,
color: Theme.of(ctx).primaryColor,
),
title: Text(
title,
style: TextStyle(
fontFamily: 'RobotoCondensed',
fontSize: 16,
fontWeight: FontWeight.bold,
color: Theme.of(ctx).primaryColor,
),
),
onTap: tapHandler,
);
}
#override
Widget build(BuildContext context) {
final authData = Provider.of<Auth>(context, listen: false);
return Drawer(
child: SafeArea(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
buildListTile(
'Home',
Icons.home_rounded,
() {
Navigator.of(context)
.pushReplacementNamed(AuthTabBarScreen.routeName);
},
context,
),
buildListTile(
'Add user',
Icons.person_add_alt_1_rounded,
() {
// Navigator.of(context).pop();
Navigator.of(context)
.pushReplacementNamed(RegisterUserScreen.routeName);
},
context,
),
buildListTile(
'Sign Out',
Icons.exit_to_app_rounded,
() {
authData.signOut();
},
context,
),
],
),
),
),
);
}
}
Hope this is at least of help to you :D
I'm kinda new to Flutter. In main.dart file I have a logo and when I run the application, the logo fades into the screen and go to the top of the screen. I have used two animation controllers for that.
In welcome.dart file there is a code for two buttons (login and Signup) one animation controller for fade in animation to that buttons.
I need to show that when logo completes the animations, show the buttons on the screen with fade in animation.
What I have tried is put adListener to the logo animation and when logo animation completes, start the button animations. But it's not working.
Here's my code -
main.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'welcome.dart';
void main() {
runApp(MyApp());
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: ('SplashScreeen'),
home: MySplashScreen(title: 'SplashScreen'),
);
}
}
class MySplashScreen extends StatefulWidget {
MySplashScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_MySplashScreenState createState() => _MySplashScreenState();
}
class _MySplashScreenState extends State<MySplashScreen>
with TickerProviderStateMixin {
AnimationController fadeAnimationLogoController;
AnimationController moveUpAnimationLogoController;
Animation<double> fadeAnimationLogo;
Animation<Offset> moveUpAnimationLogo;
initState(){
super.initState();
fadeAnimationLogoController = AnimationController(duration: Duration(milliseconds: 1500),vsync: this);
moveUpAnimationLogoController = AnimationController(duration: Duration(milliseconds: 1000),vsync: this,);
fadeAnimationLogo =CurvedAnimation(parent: fadeAnimationLogoController, curve: Curves.easeIn);
moveUpAnimationLogo = Tween<Offset>(begin: Offset(0,0),end: Offset(0, -0.2),).animate(moveUpAnimationLogoController);
fadeAnimationLogoController.forward();
fadeAnimationLogoController.addListener((){
if(fadeAnimationLogo.status == AnimationStatus.completed){
moveUpAnimationLogoController.forward();
}
});
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: FadeTransition (
opacity: fadeAnimationLogo,
child: SlideTransition(
position: moveUpAnimationLogo,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
image: AssetImage('assets/images/csrhuntlogo.png'),
height: 300,
width: 300,
),
Text(
('C S R H U N T'),
style: TextStyle(
fontFamily: 'League Spartan',
height: 1,
fontSize: 34,
color: Colors.black,
decoration: TextDecoration.none,
),
),
Text(
('FIND PLAY EARN'),
style: TextStyle(
fontFamily: 'Montserrat',
height: 1,
fontSize: 15,
color: Colors.black,
decoration: TextDecoration.none,
),
),
],
),
),
),
);
}
}
welcome.dart
import 'package:flutter/material.dart';
class Welcome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: ('WelcomeScreen'),
home: WelcomeScreen(title: 'WelcomeScreen'),
);
}
}
class WelcomeScreen extends StatefulWidget {
WelcomeScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen>
with SingleTickerProviderStateMixin {
AnimationController fadeAnimationWelcomeController;
Animation<double> fadeAnimationWelcome;
#override
void initState() {
fadeAnimationWelcomeController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 2000),
);
fadeAnimationWelcome = CurvedAnimation(
parent: fadeAnimationWelcomeController, curve: Curves.easeIn);
super.initState();
fadeAnimationWelcomeController.forward();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: FadeTransition(
opacity: fadeAnimationWelcome,
child: Stack(
children: <Widget>[
Positioned(
top: 590,
left: 20,
child: SizedBox(
width: 350.0,
height: 50.0,
child: RaisedButton(
color: new Color.fromRGBO(255, 213, 0, 1.0),
textColor: Colors.black,
onPressed: () {},
child: Text(
'log in',
style: TextStyle(
height: 1,
fontSize: 25,
fontFamily: 'League Spartan',
),
),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
side: BorderSide(color: Colors.transparent),
),
),
),
),
Positioned(
bottom: 50,
left: 20,
child: SizedBox(
width: 350.0,
height: 50.0,
child: RaisedButton(
color: new Color.fromRGBO(255, 213, 0, 1.0),
textColor: Colors.black,
onPressed: () {},
child: Text(
'Sign up',
style: TextStyle(
height: 1,
fontSize: 25,
fontFamily: 'League Spartan',
),
),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
side: BorderSide(color: Colors.transparent),
),
),
),
),
],
),
),
);
}
}
You can copy paste run full code below
For demo purpose, I slow down animation duration to 5 seconds
You can set a bool showWelcome to control when to show SingUp button
When Move Up Logo animation complete show SignUp button with setState
code snippet
moveUpAnimationLogoController.addListener(() {
if (moveUpAnimationLogo.status == AnimationStatus.completed) {
//moveUpAnimationLogoController.forward();
setState(() {
showWelcome = true;
});
}
});
showWelcome
? Expanded(
child: WelcomeScreen(
title: "test",
),
)
: Container(),
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() {
runApp(MyApp());
SystemChrome.setSystemUIOverlayStyle(
SystemUiOverlayStyle(
statusBarColor: Colors.transparent,
statusBarBrightness: Brightness.light),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: ('SplashScreeen'),
home: MySplashScreen(title: 'SplashScreen'),
);
}
}
class MySplashScreen extends StatefulWidget {
MySplashScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_MySplashScreenState createState() => _MySplashScreenState();
}
class _MySplashScreenState extends State<MySplashScreen>
with TickerProviderStateMixin {
AnimationController fadeAnimationLogoController;
AnimationController moveUpAnimationLogoController;
Animation<double> fadeAnimationLogo;
Animation<Offset> moveUpAnimationLogo;
bool showWelcome = false;
initState() {
super.initState();
fadeAnimationLogoController =
AnimationController(duration: Duration(seconds: 5), vsync: this);
moveUpAnimationLogoController = AnimationController(
duration: Duration(seconds: 5),
vsync: this,
);
fadeAnimationLogo = CurvedAnimation(
parent: fadeAnimationLogoController, curve: Curves.easeIn);
moveUpAnimationLogo = Tween<Offset>(
begin: Offset(0, 0),
end: Offset(0, -0.2),
).animate(moveUpAnimationLogoController);
fadeAnimationLogoController.forward();
fadeAnimationLogoController.addListener(() {
if (fadeAnimationLogo.status == AnimationStatus.completed) {
moveUpAnimationLogoController.forward();
}
});
moveUpAnimationLogoController.addListener(() {
if (moveUpAnimationLogo.status == AnimationStatus.completed) {
//moveUpAnimationLogoController.forward();
setState(() {
showWelcome = true;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Container(
color: Colors.white,
child: FadeTransition(
opacity: fadeAnimationLogo,
child: SlideTransition(
position: moveUpAnimationLogo,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Image(
image: AssetImage('assets/images/csrhuntlogo.png'),
height: 300,
width: 300,
),
Text(
('C S R H U N T'),
style: TextStyle(
fontFamily: 'League Spartan',
height: 1,
fontSize: 34,
color: Colors.black,
decoration: TextDecoration.none,
),
),
Text(
('FIND PLAY EARN'),
style: TextStyle(
fontFamily: 'Montserrat',
height: 1,
fontSize: 15,
color: Colors.black,
decoration: TextDecoration.none,
),
),
],
),
),
),
),
showWelcome
? Expanded(
child: WelcomeScreen(
title: "test",
),
)
: Container(),
],
),
);
}
}
class WelcomeScreen extends StatefulWidget {
WelcomeScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen>
with SingleTickerProviderStateMixin {
AnimationController fadeAnimationWelcomeController;
Animation<double> fadeAnimationWelcome;
#override
void initState() {
fadeAnimationWelcomeController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 2000),
);
fadeAnimationWelcome = CurvedAnimation(
parent: fadeAnimationWelcomeController, curve: Curves.easeIn);
super.initState();
fadeAnimationWelcomeController.forward();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child: FadeTransition(
opacity: fadeAnimationWelcome,
child: Stack(
children: <Widget>[
Positioned(
top: 590,
left: 20,
child: SizedBox(
width: 350.0,
height: 50.0,
child: RaisedButton(
color: new Color.fromRGBO(255, 213, 0, 1.0),
textColor: Colors.black,
onPressed: () {},
child: Text(
'log in',
style: TextStyle(
height: 1,
fontSize: 25,
fontFamily: 'League Spartan',
),
),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
side: BorderSide(color: Colors.transparent),
),
),
),
),
Positioned(
bottom: 50,
left: 20,
child: SizedBox(
width: 350.0,
height: 50.0,
child: RaisedButton(
color: new Color.fromRGBO(255, 213, 0, 1.0),
textColor: Colors.black,
onPressed: () {},
child: Text(
'Sign up',
style: TextStyle(
height: 1,
fontSize: 25,
fontFamily: 'League Spartan',
),
),
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(18.0),
side: BorderSide(color: Colors.transparent),
),
),
),
),
],
),
),
);
}
}
I have used this bottom navigation bar library in my app and it works perfectly. But i want to maintain a back navigation with the back button in android phones like for example in the Google Play Store bottom navigation where if we navigate through the bottom navigation the animation changes and also if we navigate back through the back button the animation changes the way before.
I have tried this article which is somewhat doing what i want but the animations are not working.
This is my stateful widget where my bottom nav bar is,
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int currentIndex;
final PageStorageBucket bucket = PageStorageBucket();
#override
void initState() {
// TODO: implement initState
super.initState();
currentIndex = 0;
}
void changePage(int index) {
setState(() {
currentIndex = index;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey.shade300,
resizeToAvoidBottomInset : false,
body:
new Stack(
children: <Widget>[
new Offstage(
offstage: currentIndex != 0,
child: new TickerMode(
enabled: currentIndex == 0,
child: new MaterialApp(home: new HomePage()),
),
),
new Offstage(
offstage: currentIndex != 1,
child: new TickerMode(
enabled: currentIndex == 1,
child: new MaterialApp(home: new StayPage()),
),
),
new Offstage(
offstage: currentIndex != 2,
child: new TickerMode(
enabled: currentIndex == 2,
child: new MaterialApp(home: new TravelPage()),
),
),
new Offstage(
offstage: currentIndex != 3,
child: new TickerMode(
enabled: currentIndex == 3,
child: new MaterialApp(home: new MorePage()),
),
),
],
),
floatingActionButton: Visibility(
visible: _isVisible,
child: Container(
height: 100.0,
width: 85.0,
// margin: EdgeInsets.only(bottom: 5.0),
child: FittedBox(
child: FloatingActionButton.extended(
onPressed: () {
setState(() {});
},
elevation: 20.0,
icon: Icon(Icons.add),
label: Text(
"Plan",
style: TextStyle(
fontFamily: "OpenSansBold",
),
),
backgroundColor: Colors.red,
),
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
bottomNavigationBar: Visibility(
visible: _isVisible,
child: BubbleBottomBar(
hasInk: true,
fabLocation: BubbleBottomBarFabLocation.end,
opacity: .2,
currentIndex: currentIndex,
onTap: changePage,
elevation: 15,
items: <BubbleBottomBarItem>[
BubbleBottomBarItem(
backgroundColor: Colors.red,
icon: Icon(
Icons.home,
color: Colors.black,
),
activeIcon: Icon(
Icons.home,
color: Colors.red,
),
title: Text(
"Home",
style: TextStyle(
fontFamily: "OpenSans",
),
)),
BubbleBottomBarItem(
backgroundColor: Colors.deepPurple,
icon: Icon(
Icons.hotel,
color: Colors.black,
),
activeIcon: Icon(
Icons.hotel,
color: Colors.deepPurple,
),
title: Text(
"Stay",
style: TextStyle(
fontFamily: "OpenSans",
),
),
),
BubbleBottomBarItem(
backgroundColor: Colors.indigo,
icon: Icon(
Icons.card_travel,
color: Colors.black,
),
activeIcon: Icon(
Icons.card_travel,
color: Colors.indigo,
),
title: Text(
"Travel",
style: TextStyle(
fontFamily: "OpenSans",
),
),
),
BubbleBottomBarItem(
backgroundColor: Colors.green,
icon: Icon(
Icons.more,
color: Colors.black,
),
activeIcon: Icon(
Icons.more,
color: Colors.green,
),
title: Text(
"More",
style: TextStyle(
fontFamily: "OpenSans",
),
),
),
],
),
),
);
}
}
It is not necessary that i have to use this library, i just want to implement a bottom navigation bar and when navigating back through using the android back button the animations must work.
Any kind of help would be appreciated! Thanks!
Solved my problem. I used the medium post by Swav Kulinski which i pointed out in my question earlier.
The code is as follows,
class NavBar extends StatefulWidget {
#override
_NavBarState createState() => _NavBarState();
}
class _NavBarState extends State<NavBar> {
final navigatorKey = GlobalKey<NavigatorState>();
int currentIndex;
final PageStorageBucket bucket = PageStorageBucket();
#override
void initState() {
// TODO: implement initState
super.initState();
currentIndex = 0;
}
void changePage(int index) {
navigatorKey.currentState.pushNamed(pagesRouteFactories.keys.toList()[index]);
setState(() {
currentIndex = index;
});
}
Future<bool> _onWillPop() {
if(currentIndex == 3){
changePage(2);
} else if(currentIndex == 2){
changePage(1);
} else if(currentIndex == 1){
changePage(0);
} else if(currentIndex == 0){
return Future.value(false);
}
return Future.value(true);
}
final pagesRouteFactories = {
"/": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("HomePage",style: Theme.of(context).textTheme.body1,),
),
),
"takeOff": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("Take Off",style: Theme.of(context).textTheme.body1,),
),
),
"landing": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("Landing",style: Theme.of(context).textTheme.body1,),
),
),
"settings": () => MaterialPageRoute(
builder: (context) => Center(
child: Text("Settings",style: Theme.of(context).textTheme.body1,),
),
),
};
#override
Widget build(BuildContext context) {
return MaterialApp(
home: WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
body: _buildBody(),
bottomNavigationBar: _buildBottomNavigationBar(context),
),
),
);
}
Widget _buildBody() =>
MaterialApp(
navigatorKey: navigatorKey,
onGenerateRoute: (route) => pagesRouteFactories[route.name]()
);
Widget _buildBottomNavigationBar(context) => BottomNavigationBar(
items: [
_buildBottomNavigationBarItem("Home", Icons.home),
_buildBottomNavigationBarItem("Take Off", Icons.flight_takeoff),
_buildBottomNavigationBarItem("Landing", Icons.flight_land),
_buildBottomNavigationBarItem("Settings", Icons.settings)
],
currentIndex: currentIndex,
onTap: changePage,
);
_buildBottomNavigationBarItem(name, icon) => BottomNavigationBarItem(
icon: Icon(icon),
title: Text(name),
backgroundColor: Colors.black45,
activeIcon: Icon(icon)
);
}
I do not know if this is the right approach though. If anyone want to suggest me better option please let me know.