flutter scrolling does not work: ListView and SingleChildScrollView - flutter

I have been reading solutions for making my screen scroll without success. Below is my code:
'''
class WelcomeScreen extends StatefulWidget {
static const String id = 'welcome_screen';
#override
_WelcomeScreenState createState() => _WelcomeScreenState();
}
class _WelcomeScreenState extends State<WelcomeScreen>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation animation;
#override
void initState() {
super.initState();
controller =
AnimationController(duration: Duration(seconds: 1), vsync: this);
animation = ColorTween(begin: Colors.blueGrey, end: Colors.white)
.animate(controller);
controller.forward();
controller.addListener(() {
setState(() {});
});
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: animation.value,
body: Padding(
padding: EdgeInsets.symmetric(horizontal: 24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Row(
children: <Widget>[
Hero(
tag: 'logo',
child: Container(
child: Image.asset('images/logo.png'),
height: 60.0,
),
),
TypewriterAnimatedTextKit(
text: ['Tonnah'],
textStyle: TextStyle(
fontSize: 45.0,
fontWeight: FontWeight.w900,
),
),
],
),
SizedBox(
height: 48.0,
),
RoundedButton(
title: 'Log In',
colour: Colors.lightBlueAccent,
onPressed: () {
Navigator.pushNamed(context, LoginScreen.id);
},
),
RoundedButton(
title: 'Register',
colour: Colors.blueAccent,
onPressed: () {
Navigator.pushNamed(context, RegistrationScreen.id);
},
),
],
),
),
);
}
}
'''
I have tried ListView and SingleChildScrollView but nothing works. This is a registration page that I will use to capture information about the user. I don't know if this is the best way of doing this or if I should be getting the user to fill out a profile after they register with their email and password.
I am new to flutter and mobile app development so please help?
TIA

Just wrap your Column with SingleChildScrollView()

Related

Flutter Animation - Card Flip without using pre defined packages

I'm trying to flip a card from front to back and back to front without using the dependencies, but could not implement. I have seen where people have used a pre defined Flip Card package but without the dependency I'm finding trouble. Please help me out.
I want the card to flip to back as soon as I click on the "Icon Button" and back as soon as I click "Go Back" Button. I tried the idea without using the animation and is working just fine, but how do I implement the flip animation is what I feel is difficult.
class NotificationItemCard extends StatefulWidget {
const NotificationItemCard({
Key? key,
}) : super(key: key);
#override
State<NotificationItemCard> createState() => _NotificationItemCardState();
}
class _NotificationItemCardState extends State<NotificationItemCard> {
late bool showCardFrontSide;
#override
void initState() {
showCardFrontSide = true;
super.initState();
}
void onChangeView() {
setState(() {
showCardFrontSide = !showCardFrontSide;
});
}
#override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
height: 140.h,
decoration: BoxDecoration(
border: Border.all(color: Colors.black),
borderRadius: BorderRadius.circular(8),
),
child: showCardFrontSide
? const NotificationCardFrontSide()
: NotificationCardBackSide(
onChangeView: onChangeView,
),
),
showCardFrontSide
? Align(
alignment: const Alignment(0.95, -1),
child: IconButton(
key: const ValueKey("IconButton"),
onPressed: onChangeView,
icon: const Icon(Icons.info_outline),
),
)
: const SizedBox.shrink()
],
);
}
}
class NotificationCardFrontSide extends StatelessWidget {
const NotificationCardFrontSide({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Row(
children: [
SizedBox(
key: const ValueKey("FrontSideSizedBox"),
width: 126.w,
child: Center(
child: CircleAvatar(
radius: 50.r,
),
),
),
SizedBox(
key: const ValueKey("FrontSideSizedTextBox"),
width: 222.w,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Premium Private LOBBY",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.ellipsis),
key: const ValueKey("FrontSideSizedTextBox1"),
),
Text(
"Prediction Deadline",
// "Prediction Deadline - ${DateConverterUtil.convert(lobby.match.start)}",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.ellipsis),
key: const ValueKey("FrontSideSizedTextBox2"),
),
Text(
"Premium Private LOBBY",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.ellipsis),
key: const ValueKey("FrontSideSizedTextBox3"),
),
SizedBox(
key: const ValueKey("FrontSideSizedButtonBox"),
width: 150.w,
height: 45.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
SizedBox(
key: const ValueKey("FrontSideButtonSizedBox"),
width: 70.w,
child: TextButton(
onPressed: () {},
child: Text(
"deny",
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
SizedBox(
width: 70.w,
child: TextButton(
onPressed: () {},
child: Text(
"deny",
style: Theme.of(context).textTheme.bodyMedium,
),
),
),
],
),
),
],
),
),
],
);
}
}
class NotificationCardBackSide extends StatelessWidget {
final VoidCallback onChangeView;
const NotificationCardBackSide({
Key? key,
required this.onChangeView,
}) : super(key: key);
Widget getTeamLogo(String image) {
return CircleAvatar(
backgroundColor: const Color(0xFFD9D9D9),
radius: 30.r,
child: Image.network(
image,
errorBuilder: (context, error, stackTrace) {
return Text(
"Error",
style: Theme.of(context).textTheme.displayMedium?.copyWith(
color: Colors.red,
),
);
},
height: 65.h,
width: 65.w,
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null) return child;
return Center(
child: Text(
"Loading...",
style: Theme.of(context).textTheme.displayMedium,
),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
SizedBox(
height: 62.h,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
getTeamLogo(""),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Premium Private LOBBY",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.clip),
key: const ValueKey("BackSideSizedText1"),
),
Text(
"Prediction Deadline",
// "Prediction Deadline - ${DateConverterUtil.convert(lobby.match.start)}",
style: Theme.of(context).textTheme.headlineMedium?.copyWith(overflow: TextOverflow.clip),
key: const ValueKey("BackSideSizedText2"),
),
],
),
getTeamLogo(""),
],
),
),
SizedBox(
key: const ValueKey("BackSideButtonBox"),
height: 30.h,
width: 100.w,
child: OutlinedButton(
onPressed: onChangeView,
child: const Text("Go Back"),
key: const ValueKey("BackSideButtonText"),
style: ButtonStyle(
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(
8.r,
),
),
),
),
),
)
],
);
}
}
You can implement this with AnimatedBuilder and Transform, Use example below:
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: Scaffold(body: MyApp())));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> with SingleTickerProviderStateMixin {
late AnimationController _controller;
Widget _front = Card1();
Widget _back = Card2();
late Widget _card = _front;
#override
void initState() {
super.initState();
_controller = AnimationController(vsync: this, duration: Duration(milliseconds: 600));
_controller.addListener(() {
if (_controller.value >= .5 && _card != _back) {
setState(() => _card = _back);
} else if (_controller.value < .5 && _card != _front) {
setState(() => _card = _front);
}
});
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: GestureDetector(
onTap: () {
if (_controller.value == 1)
_controller.reverse(from: 1);
else
_controller.forward(from: 0);
},
child: AnimatedBuilder(
animation: _controller,
builder: (c, anim) => Transform(
transform: Matrix4.identity()
..setEntry(3, 2, 0.0025)
..rotateY(_controller.value * pi),
alignment: FractionalOffset.center,
child: _card,
),
),
),
);
}
}
class Card1 extends StatelessWidget {
const Card1({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 150,
height: 300,
color: Colors.red,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Card1'),
Text('I\'m front of the card'),
],
),
);
}
}
class Card2 extends StatelessWidget {
const Card2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Transform.scale(
scaleX: -1,
child: Container(
width: 150,
height: 300,
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is Card2'),
Text('I\'m back of the card'),
],
),
),
);
}
}
The result:
(Thanks to this answer for transform code)

How to await splash screen while loading a home screen in flutter

My application takes some time to load to the home screen, and also takes time to fetch all the data from the API. so I need a splash screen for the application. but it should wait for 3 seconds (the time that takes to load the home screen). so I want to cover the waiting time with a splash screen.
How do I achieve this?
You can also have a minimal Flutter app running while you await the more expensive initialization. Just call runApp twice!
void main () async {
runApp(SomethingAnimated());
await longTaskOne();
await longTaskTwo();
await longTaskThree();
runApp(MyRealTopLevel();
}
Yes this is perfectly legal and documented.
EDIT: I made a video about this, and also about warming up RiverPod pre-fetched data, at https://youtu.be/ob8M9c-6III.
Use you own custom image of splashscreen or design new one here.increase or decrease time but less time is better
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
// TODO: implement initState
super.initState();
startTime();
}
#override
Widget build(BuildContext context) {
// TODO: implement build
Size size = MediaQuery.of(context).size;
return SafeArea(
child: Scaffold(
body: new Stack(
alignment: Alignment.center,
children: <Widget>[
Center(
child: new Image.asset(
'assets/images/splash.png',
width: size.width,
height: size.height,
fit: BoxFit.fill,
),
),
],
),
),
);
}
startTime() async {
var _duration = new Duration(seconds: 5);
return new Timer(_duration, navigationPage);
}
void navigationPage() {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => DashBoardScreen()),
ModalRoute.withName("/login"));
}
}
You can add a image as a splashscreen using this method,
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
#override
void initState() {
super.initState();
Timer(
Duration(seconds: 5),
() => Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => Home())));
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
decoration: BoxDecoration(
color: Color.fromRGBO(20, 172, 168, 1),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.white,
radius: 60.0,
child: new Image.asset(
'assets/images/tree.jpg',
width: 70,
height: 90,
)),
Padding(
padding: EdgeInsets.only(top: 10.0),
),
Text(
'Your Text here!!',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24.0),
)
],
),
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Padding(
padding: EdgeInsets.only(top: 20.0),
),
Text(
'Your Text here!!',
softWrap: true,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white),
)
],
),
)
],
)
],
),
);
}
}
And if you want to increase or decrease the time span then you can change this
Timer(const Duration(seconds: 3).

how to fix inverted 'ok' text in flatbutton?

I'm beginner in flutter. trying to design login page. when user clicks on 'ok' button then 'ok' button gets invisible and 'approved' named button gets visible using some animation. problem is that 'ok' displayed in inverted form as shown in pic. how dI correct this issue?
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Animation class',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
State<StatefulWidget> createState() => stateClass();
}
class stateClass extends State<HomePage> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation<double> animation;
Animation<double> sizeAnimation;
int currentState = 0;
#override
void initState() {
super.initState();
animationController = AnimationController(
duration: Duration(milliseconds: 1000), vsync: this);
animation = Tween<double>(begin: 0, end: 60).animate(animationController)
..addListener(() {
setState(() {});
});
sizeAnimation = Tween<double>(begin: 0, end: 1).animate(CurvedAnimation(
parent: animationController, curve: Curves.fastOutSlowIn))
..addListener(() {
setState(() {});
});
}
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Animation login'),
),
body: Container(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
height: 100,
//color: Colors.black,
child: Center(
child: Image.asset('assets/fluttericon.png'),
)),
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: TextFormField(
decoration: InputDecoration(
labelText: 'enter your email id',
),
),
),
Container(
margin: EdgeInsets.all(10),
padding: EdgeInsets.all(10),
child: TextFormField(
obscureText: true,
decoration: InputDecoration(
labelText: 'enter your password',
),
),
),
Container(
// color: Colors.teal,
// height: 0,
child: Center(
child: Transform.scale(
scale: sizeAnimation.value - 1,
child: FlatButton(
onPressed: animationController.forward,
color: Colors.redAccent[200],
child: Text(
'ok',
style: TextStyle(fontSize: 17, color: Colors.black),
),
),
)),
),
Container(
//color: Colors.teal,
height: 80,
child: Center(
child: Transform.scale(
scale: sizeAnimation.value,
child: FlatButton(
onPressed: animationController.reverse,
color: Colors.redAccent[200],
child: Text(
'approved',
style: TextStyle(fontSize: 17, color: Colors.black),
),
),
)),
),
],
),
)
)
);
}
}
Text container
Container(
// color: Colors.teal,
// height: 0,
child: Center(
child: Transform.scale(
scale: sizeAnimation.value-1 ,
child: FlatButton(
onPressed: animationController.forward,
color: Colors.redAccent[200],
child: Text(
'ok',
style: TextStyle(fontSize: 17, color: Colors.black),
),
),
)),
),
When I change sizeAnimation.value-1 to sizeAnimation. then 'ok' word is in erect form. but ok button is not invisible.
Screenshot preview
A possible solution for what you are trying to do is to use Fade and Rotate transitions with separate controllers for each Text widget. Here's an example of that:
class ButtonTextFadeRotation extends StatefulWidget {
#override
_ButtonTextFadeRotationState createState() => _ButtonTextFadeRotationState();
}
class _ButtonTextFadeRotationState extends State<ButtonTextFadeRotation> with TickerProviderStateMixin {
AnimationController _okAnimationController;
AnimationController _approvedAnimationController;
#override
void initState() {
_okAnimationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
value: 1
);
_approvedAnimationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 200),
value: 0
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Center(
child: ClipRect(
child: RaisedButton(
onPressed: () {
_okAnimationController.reverse();
_approvedAnimationController.forward();
},
child: Stack(
alignment: Alignment.center,
children: <Widget>[
FadeTransition(
opacity: _okAnimationController,
child: RotationTransition(
turns: _okAnimationController,
alignment: Alignment.center,
child: Text('Ok'),
),
),
FadeTransition(
opacity: _approvedAnimationController,
child: RotationTransition(
turns: _approvedAnimationController,
alignment: Alignment.center,
child: Text('Approved'),
),
),
],
),
),
),
);
}
}

How to animate hiding AppBar in Flutter?

I need help with animating my AppBar.
My AppBar hides on DoubleTap, but there's no animation in it, it hides immediately. I want it to be animated. I tried to wrap my AppBar with SlideTransition and AnimatedContainer widget, but none of these work, because the error says I need a PreferredSize widget.
I would be extremely glad, if someone helped me!
I already checked out this answer, but the guy, who answered to this question, has the same problem. There's no animation. Show (slide in) or hide (slide out) flutter AppBar on screen tap
Here's the video of my AppBar:
https://streamable.com/it7ib
Here's the photo how my AppBar looks like:
Code:
import 'package:flutter/material.dart';
class GeneratedCouponScreen extends StatefulWidget {
#override
_GeneratedCouponScreenState createState() => _GeneratedCouponScreenState();
}
class _GeneratedCouponScreenState extends State<GeneratedCouponScreen> {
bool showAppBar = true;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: showAppBar ? AppBar() : null ,
backgroundColor: Colors.white,
body: GestureDetector(
onDoubleTap: () {
if (showAppBar) {
setState(() {
showAppBar = false;
});
}
else {
setState(() {
showAppBar = true;
});
}
},
child: SafeArea(
child: Container(
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('DATA WYDANIA:', style: TextStyle(color: Colors.black),),
Text('10/09/2019', style: TextStyle(color: Colors.black))
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('UNIKALNY KOD:', style: TextStyle(color: Colors.black)),
Text('e-86-tC-9', style: TextStyle(color: Colors.black))
],
)
],
),
Column(
children: [
SizedBox(height: 8.0),
Image.asset('assets/images/coupon_hamburger.png',)
],
)
],
)
),
)));
}
}
One way of doing it is by using stack and AnimatedBuilder.
class GeneratedCouponScreen extends StatefulWidget {
#override
_GeneratedCouponScreenState createState() => _GeneratedCouponScreenState();
}
class _GeneratedCouponScreenState extends State<GeneratedCouponScreen>
with SingleTickerProviderStateMixin {
AnimationController _controller;
#override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(milliseconds: 300),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: SafeArea(
child: AnimatedBuilder(
animation: _controller,
builder: (context, child) => Stack(
children: <Widget>[
Transform.translate(
offset: Offset(0, -_controller.value * 64),
child: Container(
height: 56.0,
child: AppBar(
title: Text('Title'),
leading: Icon(
Icons.arrow_back,
),
),
),
),
GestureDetector(
onDoubleTap: () {
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: Container(
margin: const EdgeInsets.only(top: 56.0),
padding: EdgeInsets.all(16.0),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'DATA WYDANIA:',
style: TextStyle(color: Colors.black),
),
Text('10/09/2019',
style: TextStyle(color: Colors.black))
],
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('UNIKALNY KOD:',
style: TextStyle(color: Colors.black)),
Text('e-86-tC-9',
style: TextStyle(color: Colors.black))
],
)
],
),
Column(
children: [
SizedBox(height: 8.0),
Image.network(
'http://via.placeholder.com/640x360',
)
],
)
],
),
),
),
],
),
),
),
);
}
}
First you have to create a new class
class MyAppBar extends StatefulWidget implements PreferredSizeWidget {
num height = 70.0;
#override
_MyAppBarState createState() => _MyAppBarState();
#override
Size get preferredSize => Size.fromHeight(height);
}
class _MyAppBarState extends State<MyAppBar> {
#override
Widget build(BuildContext context) {
return Container(
child: GestureDetector(
onDoubleTap: () {
// Your logic here
// You can do any stuff like animating your this appBar
//e.g: using Opacitiy or Transform and any other Widget depending on what kind of animation you want
// You can also descrease height by calling widget.height
},
child: AppBar(
//Your logic here
),
),
);
}
}
Then call it like this
return Scaffold(
appBar: MyAppBar(),);

How to make the activity stack null in flutter?

I have 4 walkthrough screens, on reaching the ending of the screens when i go to the homepage of my app which is named as TestScreen here,when i press the back button in my phone i again go back to the walkthrough pages which i dont want and it throws an exception too ("Failed assertion: line 1554 pos 12: '!_debugLocked': is not true."). So i was thinking if i make the activity stack null after coming to TestScreen it might work but i am not able to do so. Please help me.
Main.dart
library flutter_walkthrough;
import 'package:flutter/material.dart';
import 'package:comp_apps/walkthrough.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
final List<Walkthrough> list = [
Walkthrough(
title: "Title 1",
content: "Content 1",
imageIcon: Icons.restaurant_menu,
),
Walkthrough(
title: "Title 2",
content: "Content 2",
imageIcon: Icons.search,
),
Walkthrough(
title: "Title 3",
content: "Content 3",
imageIcon: Icons.shopping_cart,
),
Walkthrough(
title: "Title 4",
content: "Content 4",
imageIcon: Icons.verified_user,
),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
home: IntroScreen(list, MaterialPageRoute(builder: (context)=>
TestScreen())).,
);
}
}
class TestScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Hello"),
automaticallyImplyLeading: false,
),
);
}
}
class IntroScreen extends StatefulWidget {
final List<Walkthrough> walkthroughList;
final MaterialPageRoute pageRoute;
IntroScreen(this.walkthroughList, this.pageRoute);
void skipPage(BuildContext context) {
Navigator.push(context, pageRoute);
}
#override
_IntroScreenState createState() => _IntroScreenState();
}
class _IntroScreenState extends State<IntroScreen> {
final PageController controller = new PageController();
int currentPage = 0;
bool lastPage = false;
void _onPageChanged(int page) {
setState(() {
currentPage = page;
if (currentPage == widget.walkthroughList.length - 1) {
lastPage = true;
} else {
lastPage = false;
}
});
}
#override
Widget build(BuildContext context) {
return Container(
color: Color(0xFFEEEEEE),
padding: const EdgeInsets.all(10.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Expanded(
child: Container(),
flex: 1,
),
Expanded(
flex: 3,
child: PageView(
children: widget.walkthroughList,
controller: controller,
onPageChanged: _onPageChanged,
),
),
Expanded(
flex: 1,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
FlatButton(
child: Text(
lastPage ? "" : "SKIP",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 16.0),
),
onPressed: () => lastPage ? null : widget.skipPage(context),
),
FlatButton(
child: Text(
lastPage ? "GOT IT" : "NEXT",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 16.0,
),
),
onPressed: () => lastPage
? widget.skipPage(context)
: controller.nextPage(
duration: Duration(milliseconds: 300),
curve: Curves.easeIn),
)
],
),
)
],
),
);
}
}
Walkthrough.dart
import 'package:flutter/material.dart';
class Walkthrough extends StatefulWidget {
final title;
final content;
final imageIcon;
final imagecolor;
Walkthrough({this.title, this.content, this.imagecolor, this.imageIcon});
#override
_WalkthroughState createState() => _WalkthroughState();
}
class _WalkthroughState extends State<Walkthrough>
with SingleTickerProviderStateMixin {
Animation animation;
AnimationController animationController;
#override
void initState() {
// TODO: implement initState
super.initState();
animationController = AnimationController(vsync: this,duration:
Duration(milliseconds: 500));
animation = Tween(
begin: -250.0, end: 0.0).animate(CurvedAnimation(parent:
animationController, curve: Curves.easeInOut));
animation.addListener(() => setState(() {}));
animationController.forward();
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
animationController.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.all(20.0),
child: Material(
animationDuration: Duration(milliseconds: 500),
elevation: 2.0,
borderRadius: BorderRadius.all(Radius.circular(5.0)),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Transform(
transform: Matrix4.translationValues(animation.value, 0.0, 0.0),
child: Text(widget.title,style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
color: Colors.black
),),
),
Transform(
transform: Matrix4.translationValues(animation.value, 0.0, 0.0),
child: Text(widget.content,
softWrap: true,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.normal,
fontSize: 15.0,
color: Colors.black,
),),
),
Icon(
widget.imageIcon,
size: 100.0,
color: widget.imagecolor,
)
],
),
),
);
}
}