i want to create some thing like this flip container flutter - flutter

it has three container when i tap on it it change to next flip I tried with flip_card package and it has only front and back but I need extra one

flip_board (https://pub.dev/packages/flip_board#middle-flip) package does exactly what you want.
Sample Code : -
FlipWidget({
flipType: FlipType.spinFlip, // Change flip effect
itemStream: _stream, // it is basically the length of Stacked Widgets.
itemBuilder: _itemBuilder, // Body of your Widget
flipDirection: AxisDirection.right, // flip up, down, left, right.
});
This package has many more methods and Widget types, to learn more about it vist the official page : - https://pub.dev/packages/flip_board#middle-flip
Complete Code : -
import 'dart:async';
import 'package:flip_board/flip_widget.dart';
import 'package:flutter/material.dart';
void main() => runApp(const MaterialApp(home: FlipPage()));
class FlipPage extends StatefulWidget {
const FlipPage({super.key});
#override
State<FlipPage> createState() => _FlipPageState();
}
class _FlipPageState extends State<FlipPage> {
#override
Widget build(BuildContext context) {
var spinController = StreamController<int>.broadcast();
bool containerClicked = false;
int nextSpinValue = 0;
int? widgetIndex = 0;
void spin() => spinController.add(++nextSpinValue);
return Scaffold(
body: Center(
child: FlipWidget(
initialValue: nextSpinValue,
itemStream: spinController.stream,
flipType: FlipType.spinFlip,
itemBuilder: (_, index) {
return GestureDetector(
onTap: (() async {
if (!containerClicked) {
containerClicked = true;
widgetIndex = index as int?;
if (widgetIndex! < 2) {
spin();
} else {
nextSpinValue = 0;
spinController.add(nextSpinValue);
}
await Future.delayed(const Duration(milliseconds: 500));
containerClicked = false;
}
}),
child: Container(
color: index == 0
? Colors.red[100]
: index == 1
? Colors.amber[100]
: Colors.blue[100],
height: 200,
width: 200,
alignment: Alignment.center,
child: Text(
'Widget $index',
style: const TextStyle(fontSize: 18),
)));
},
flipDirection: AxisDirection.up,
),
),
);
}
}
Output : -

As my opinion you should use animationOpacity like this :
i made one demo for you please check it.
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _showFirstSide = false;
bool _showSecondSide = false;
bool _showThirdSide = false;
#override
void initState() {
super.initState();
_showFirstSide = true;
_showSecondSide = false;
_showThirdSide = false;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(""),
centerTitle: true,
),
body: Center(
child: SizedBox(
height: 100,
width: 100,
// constraints: BoxConstraints.tight(size),
child: _buildFlipAnimation(),
),
),
);
}
void _switchCard() {
setState(() {
if (_showFirstSide) {
_showFirstSide = !_showFirstSide;
_showSecondSide = true;
_showFirstSide = false;
} else if (_showSecondSide) {
_showSecondSide = !_showSecondSide;
_showThirdSide = true;
_showFirstSide = false;
} else if (_showThirdSide) {
_showThirdSide = !_showThirdSide;
_showFirstSide = true;
_showSecondSide = false;
}
});
}
Widget _buildFlipAnimation() {
return GestureDetector(
onTap: _switchCard,
child: Stack(
children: [
AnimatedOpacity(
curve: Curves.easeInBack,
duration: const Duration(milliseconds: 700),
opacity: _showFirstSide ? 1 : 0,
child: Container(
color: Colors.black,
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width / 2,
),
),
AnimatedOpacity(
curve: Curves.easeIn.flipped,
duration: const Duration(milliseconds: 700),
opacity: _showSecondSide ? 1 : 0,
child: Container(
color: Colors.blue,
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width / 2,
),
),
AnimatedOpacity(
curve: Curves.easeOut,
duration: const Duration(milliseconds: 400),
opacity: _showThirdSide ? 1 : 0,
child: Container(
color: Colors.pink,
height: MediaQuery.of(context).size.height / 2,
width: MediaQuery.of(context).size.width / 2,
),
),
],
),
);
}
}

Related

How to drag multiple objects inside a Container

I'm trying to have multiple images inside a big container and be able to move them around and rotate them, as shown in the image below:
I've been playing around with CostumePainter and this is my result whilst following this guide and
Does anyone have an idea on how to do this with Images and multiple of them?
My code:
dynamic _balls;
double xPos = 100;
double yPos = 100;
bool isClick = false;
#override
Widget build(BuildContext context) {
_balls = _paint(xPosition: xPos, yPosition: yPos, ballRad: 20);
return Scaffold(
appBar: AppBar(
title: const Text("Drag and Drop"),
),
body: Center(
child: GestureDetector(
onHorizontalDragDown: (details) {
setState(() {
if (_balls.isBallRegion(
details.localPosition.dx, details.localPosition.dy)) {
isClick = true;
}
});
},
onHorizontalDragEnd: (details) {
setState(() {
isClick = false;
});
},
onHorizontalDragUpdate: (details) {
if (isClick) {
setState(() {
xPos = details.localPosition.dx;
yPos = details.localPosition.dy;
});
}
},
child: Container(
height: 300,
width: 300,
color: Colors.lightBlueAccent,
child: CustomPaint(
painter: _balls,
),
),
),
),
);
}
I followed this guide and it helped me, btw this is the blog.
Here is the code btw:
// #dart=2.9
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomePage(),
);
}
}
class ContainerList {
double height;
double width;
double scale;
double rotation;
double xPosition;
double yPosition;
ContainerList({
this.height,
this.rotation,
this.scale,
this.width,
this.xPosition,
this.yPosition,
});
}
class HomePage extends StatefulWidget {
const HomePage({Key key}) : super(key: key);
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<ContainerList> list = [];
Offset _initPos;
Offset _currentPos = Offset(0, 0);
double _currentScale;
double _currentRotation;
Size screen;
#override
void initState() {
screen = Size(400, 500);
list.add(ContainerList(
height: 200.0,
width: 200.0,
rotation: 0.0,
scale: 1.0,
xPosition: 0.1,
yPosition: 0.1,
));
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
height: 500.0,
color: Colors.blue.withOpacity(0.8),
width: double.infinity,
child: Stack(
children: list.map((value) {
return GestureDetector(
onScaleStart: (details) {
if (value == null) return;
_initPos = details.focalPoint;
_currentPos = Offset(value.xPosition, value.yPosition);
_currentScale = value.scale;
_currentRotation = value.rotation;
},
onScaleUpdate: (details) {
if (value == null) return;
final delta = details.focalPoint - _initPos;
final left = (delta.dx / screen.width) + _currentPos.dx;
final top = (delta.dy / screen.height) + _currentPos.dy;
setState(() {
value.xPosition = Offset(left, top).dx;
value.yPosition = Offset(left, top).dy;
value.rotation = details.rotation + _currentRotation;
value.scale = details.scale * _currentScale;
});
},
child: Stack(
children: [
Positioned(
left: value.xPosition * screen.width,
top: value.yPosition * screen.height,
child: Transform.scale(
scale: value.scale,
child: Transform.rotate(
angle: value.rotation,
child: Container(
height: value.height,
width: value.width,
child: FittedBox(
fit: BoxFit.fill,
child: Listener(
onPointerDown: (details) {
// if (_inAction) return;
// _inAction = true;
// _activeItem = val;
_initPos = details.position;
_currentPos =
Offset(value.xPosition, value.yPosition);
_currentScale = value.scale;
_currentRotation = value.rotation;
},
onPointerUp: (details) {
// _inAction = false;
},
child: Container(
height: value.height,
width: value.width,
color: Colors.red,
),
// child: Image.network(value.name),
),
),
),
),
),
)
],
),
);
}).toList(),
),
),
);
}
}
As a learning exercise, I created a basic flutter app that at least demonstrates dragging around a number of independent items and doing a couple of things like selecting, deleting, and re-ordering. The rotation function is a little buggy.
https://github.com/SpiRaiL/emoji_party_2

How this animation can be implemented?

What is the best approach for this animation?
Row + Flexible + AnimatedSize + Image ?
or Rive. Thank you in advance.
You can do this using an animated container when one card is selected then another card's height/width will be decreased and the selected container height/width will be increased.
Flutter Cookbook - Animate the properties of a container
I just worked hard to make like this, this will surely help you
import 'dart:math';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: Animation(),
));
}
class Animation extends StatefulWidget {
#override
_AnimationState createState() => _AnimationState();
}
class _AnimationState extends State<Animation> {
Map<String, String> map1 = {"0": 'zero', "1": "One", "2": "Two"};
int selectedIndex = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
color: Colors.white,
padding: EdgeInsets.only(left: 6),
child: Animated(
items: map1,
animationDuration: const Duration(milliseconds: 400),
onTap: (index) {
setState(() {
selectedIndex = index;
});
}),
),
),
);
}
}
class Animated extends StatefulWidget {
var items;
final Duration animationDuration;
final Function onTap;
Animated(
{this.items,
this.animationDuration = const Duration(milliseconds: 300),
required this.onTap});
#override
_AnimatedState createState() => _AnimatedState();
}
class _AnimatedState extends State<Animated>
with TickerProviderStateMixin {
int selectedIndex = 0;
late double height = 100, width = 100;
#override
Widget build(BuildContext context) {
/* height = MediaQuery.of(context).size.height;
width = MediaQuery.of(context).size.width;*/
return Container(
height: 100,
width: double.infinity,
padding: EdgeInsets.only(top: 2, bottom: 2),
child: ListView(
scrollDirection: Axis.horizontal,
children: _buildItems(),
),
);
}
List<Widget> _buildItems() {
List<Widget> _Items = [];
for (int i = 0; i < widget.items.length; i++) {
bool isSelected = selectedIndex == i;
_Items.add(
InkWell(
splashColor: Colors.transparent,
onTap: () {
setState(() {
selectedIndex = i;
widget.onTap(selectedIndex);
});
},
child: AnimatedContainer(
width: isSelected == true ? width + 60 : width,
margin: EdgeInsets.only(left: 2, right: 2),
padding:
const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
duration: widget.animationDuration,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(2.0)),
gradient: LinearGradient(
colors: [
Colors.blue,
Colors.primaries[Random().nextInt(Colors.primaries.length)]
],
),
),
child: Text(widget.items[i.toString()]),
),
),
);
}
return _Items;
}
}
Try this if you want to animate the container
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(const AnimatedContainerApp());
class AnimatedContainerApp extends StatefulWidget {
const AnimatedContainerApp({super.key});
#override
State<AnimatedContainerApp> createState() => _AnimatedContainerAppState();
}
class _AnimatedContainerAppState extends State<AnimatedContainerApp> {
// Define the various properties with default values. Update these properties
// when the user taps a FloatingActionButton.
double _width = 50;
double _height = 50;
Color _color = Colors.green;
BorderRadiusGeometry _borderRadius = BorderRadius.circular(8);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('AnimatedContainer Demo'),
),
body: Center(
child: AnimatedContainer(
// Use the properties stored in the State class.
width: _width,
height: _height,
decoration: BoxDecoration(
color: _color,
borderRadius: _borderRadius,
),
// Define how long the animation should take.
duration: const Duration(seconds: 1),
// Provide an optional curve to make the animation feel smoother.
curve: Curves.fastOutSlowIn,
),
),
floatingActionButton: FloatingActionButton(
// When the user taps the button
onPressed: () {
// Use setState to rebuild the widget with new values.
setState(() {
// Create a random number generator.
final random = Random();
// Generate a random width and height.
_width = random.nextInt(300).toDouble();
_height = random.nextInt(300).toDouble();
// Generate a random color.
_color = Color.fromRGBO(
random.nextInt(256),
random.nextInt(256),
random.nextInt(256),
1,
);
// Generate a random border radius.
_borderRadius =
BorderRadius.circular(random.nextInt(100).toDouble());
});
},
child: const Icon(Icons.play_arrow),
),
),
);
}
}

How to create flutter Custom Curved Navigation Drawer

I am creating custom navigation drawer. I want add curved animation onItemSelected.
But I have no idea how to create curved animation effect. I have tried many plugins but could not find plugin which related with this design. Here is my example code
import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
void main() {
runApp(
MaterialApp(
home: MyApp(),
),
);
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
List<bool> selected = [true, false, false, false, false];
class _MyAppState extends State<MyApp> {
List<IconData> icon = [
Feather.wind,
Feather.folder,
Feather.monitor,
Feather.lock,
Feather.mail,
];
void select(int n) {
for (int i = 0; i < 5; i++) {
if (i == n) {
selected[i] = true;
} else {
selected[i] = false;
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
Container(
color: Colors.white,
),
Container(
margin: EdgeInsets.all(8.0),
height: MediaQuery.of(context).size.height,
width: 101.0,
decoration: BoxDecoration(
color: Color(0xff332A7C),
borderRadius: BorderRadius.circular(20.0),
),
child: Stack(
children: [
Positioned(
top: 110,
child: Column(
children: icon
.map(
(e) => NavBarItem(
icon: e,
selected: selected[icon.indexOf(e)],
onTap: () {
setState(() {
select(icon.indexOf(e));
});
},
),
)
.toList(),
),
),
],
),
),
],
),
);
}
}
class NavBarItem extends StatefulWidget {
final IconData icon;
final Function onTap;
final bool selected;
NavBarItem({
this.icon,
this.onTap,
this.selected,
});
#override
_NavBarItemState createState() => _NavBarItemState();
}
class _NavBarItemState extends State<NavBarItem> with TickerProviderStateMixin {
AnimationController _controller1;
AnimationController _controller2;
Animation<double> _anim1;
Animation<double> _anim2;
Animation<double> _anim3;
Animation<Color> _color;
bool hovered = false;
#override
void initState() {
super.initState();
_controller1 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 250),
);
_controller2 = AnimationController(
vsync: this,
duration: Duration(milliseconds: 275),
);
_anim1 = Tween(begin: 101.0, end: 75.0).animate(_controller1);
_anim2 = Tween(begin: 101.0, end: 25.0).animate(_controller2);
_anim3 = Tween(begin: 101.0, end: 50.0).animate(_controller2);
_color = ColorTween(end: Color(0xff332a7c), begin: Colors.white)
.animate(_controller2);
_controller1.addListener(() {
setState(() {});
});
_controller2.addListener(() {
setState(() {});
});
}
#override
void didUpdateWidget(NavBarItem oldWidget) {
super.didUpdateWidget(oldWidget);
if (!widget.selected) {
Future.delayed(Duration(milliseconds: 10), () {
//_controller1.reverse();
});
_controller1.reverse();
_controller2.reverse();
} else {
_controller1.forward();
_controller2.forward();
Future.delayed(Duration(milliseconds: 10), () {
//_controller2.forward();
});
}
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
widget.onTap();
},
child: MouseRegion(
onEnter: (value) {
setState(() {
hovered = true;
});
},
onExit: (value) {
setState(() {
hovered = false;
});
},
child: Container(
width: 101.0,
color:
hovered && !widget.selected ? Colors.white12 : Colors.transparent,
child: Stack(
children: [
Container(
height: 80.0,
width: 101.0,
child: Center(
child: Icon(
widget.icon,
color: _color.value,
size: 18.0,
),
),
),
],
),
),
),
);
}
}
I want create Navigation Drawer like this image given in above example. How can I achieve this please help me for it Thank you in advance.

How to have the drawer push the content instead of going on top of it?

I'm trying to build something similar to the slack app (see screenshot below) where the navigation drawer pushes the screen away instead of going on top.
I've been trying with the Drawer component without success. I've also looked at PageView but it seems that the children need to take 100% of the width.
Does someone have an idea of how to implement it?
EDIT
A similar result can be achieved with a Stack and AnimatedPositioned
class SlidingDrawer extends StatefulWidget {
final Widget drawer;
final Widget child;
final int swipeSensitivity;
final double drawerRatio;
final Color overlayColor;
final double overlayOpacity;
final int animationDuration;
final Curve animationCurve;
SlidingDrawer({
Key key,
#required this.drawer,
#required this.child,
this.swipeSensitivity = 25,
this.drawerRatio = 0.8,
this.overlayColor = Colors.black,
this.overlayOpacity = 0.5,
this.animationDuration = 500,
this.animationCurve = Curves.ease,
}) : super(key: key);
#override
_SlidingDrawerState createState() => _SlidingDrawerState();
}
class _SlidingDrawerState extends State<SlidingDrawer> {
bool _opened = false;
void open() {
setState(() {
_opened = true;
});
}
void close() {
setState(() {
_opened = false;
});
}
#override
Widget build(BuildContext context) {
final width = MediaQuery.of(context).size.width;
final height = MediaQuery.of(context).size.height;
final drawerWidth = width * widget.drawerRatio;
return GestureDetector(
onHorizontalDragUpdate: (details) {
if (details.delta.dx > widget.swipeSensitivity) {
open();
} else if (details.delta.dx < -widget.swipeSensitivity) {
close();
}
},
child: SizedBox(
width: width,
height: height,
child: Stack(
children: [
AnimatedPositioned(
width: drawerWidth,
height: height,
left: _opened ? 0 : -drawerWidth,
duration: Duration(milliseconds: widget.animationDuration),
curve: widget.animationCurve,
child: Container(
color: Colors.amber,
child: widget.drawer,
),
),
AnimatedPositioned(
height: height,
width: width,
left: _opened ? drawerWidth : 0,
duration: Duration(milliseconds: widget.animationDuration),
curve: widget.animationCurve,
child: Stack(
fit: StackFit.expand,
children: [
widget.child,
AnimatedSwitcher(
duration: Duration(milliseconds: widget.animationDuration),
switchInCurve: widget.animationCurve,
switchOutCurve: widget.animationCurve,
child: _opened
? GestureDetector(
onTap: () {
setState(() {
_opened = false;
});
},
child: Container(
color: widget.overlayColor.withOpacity(
widget.overlayOpacity,
),
),
)
: null,
)
],
),
),
],
),
),
);
}
}
ORIGINAL ANSWER
As pointed out by #Yadu in the comment
you could use Single child horizontal scroll view (with disabled scroll physics) with Scrollable.ensureVisible(context) to show the menu
using an horizontal scroll view is working.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _drawerOpened = false;
final drawerKey = new GlobalKey();
final mainKey = new GlobalKey();
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
child: Row(
children: [
Container(
key: drawerKey,
color: Colors.green,
width: MediaQuery.of(context).size.width * 0.8,
),
SizedBox(
key: mainKey,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Scaffold(
appBar: AppBar(
title: Text("My Page"),
leading: IconButton(
icon: Icon(Icons.menu),
onPressed: _toggleDrawer,
),
),
body: Container(
color: Colors.yellow,
width: MediaQuery.of(context).size.width,
),
),
),
],
),
);
}
void _toggleDrawer() {
setState(() {
_drawerOpened = !_drawerOpened;
});
if (_drawerOpened) {
Scrollable.ensureVisible(drawerKey.currentContext);
} else {
Scrollable.ensureVisible(mainKey.currentContext);
}
}
}

How can I add another part to this page and make it so when I press on one question it opens up a different set of questions? Complex UI

Marcinus created this:
https://user-images.githubusercontent.com/16286046/72802272-afed4e00-3c4b-11ea-80f7-e98717babbb2.gif
I want to add another page to the sets of questions and make it so that when I pick a certain question, it opens up a certain question. Im quite new to flutter so any help would be appreciated
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
theme: ThemeData(primarySwatch: Colors.blue, brightness: Brightness.dark),
home: FlightsStepper(),
));
}
class FlightsStepper extends StatefulWidget {
#override
_FlightsStepperState createState() => _FlightsStepperState();
}
class _FlightsStepperState extends State<FlightsStepper> {
int pageNumber = 1;
#override
Widget build(BuildContext context) {
Widget page = pageNumber == 1
? Page(
key: Key('page1'),
onOptionSelected: () => setState(() => pageNumber = 2),
question:
'Do you typically fly for business, personal reasons, or some other reason?',
answers: <String>['Business', 'Personal', 'Others'],
number: 1,
)
: Page(
key: Key('page2'),
onOptionSelected: () => setState(() => pageNumber = 1),
question: 'How many hours is your average flight?',
answers: <String>[
'Less than two hours',
'More than two but less than five hours',
'Others'
],
number: 2,
);
return Scaffold(
body: Container(
width: double.infinity,
height: double.infinity,
decoration: backgroundDecoration,
child: SafeArea(
child: Stack(
children: <Widget>[
ArrowIcons(),
Plane(),
Line(),
Positioned.fill(
left: 32.0 + 8,
child: AnimatedSwitcher(
child: page,
duration: Duration(milliseconds: 250),
),
),
],
),
),
),
);
}
}
class Line extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Positioned(
left: 32.0 + 32 + 8,
top: 40,
bottom: 0,
width: 1,
child: Container(color: Colors.white.withOpacity(0.5)),
);
}
}
class Page extends StatefulWidget {
final int number;
final String question;
final List<String> answers;
final VoidCallback onOptionSelected;
const Page(
{Key key,
#required this.onOptionSelected,
#required this.number,
#required this.question,
#required this.answers})
: super(key: key);
#override
_PageState createState() => _PageState();
}
class _PageState extends State<Page> with SingleTickerProviderStateMixin {
List<GlobalKey<_ItemFaderState>> keys;
int selectedOptionKeyIndex;
AnimationController _animationController;
#override
void initState() {
super.initState();
keys = List.generate(
2 + widget.answers.length,
(_) => GlobalKey<_ItemFaderState>(),
);
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 500),
);
onInit();
}
Future<void> animateDot(Offset startOffset) async {
OverlayEntry entry = OverlayEntry(
builder: (context) {
double minTop = MediaQuery.of(context).padding.top + 52;
return AnimatedBuilder(
animation: _animationController,
builder: (context, child) {
return Positioned(
left: 26.0 + 32 + 8,
top: minTop +
(startOffset.dy - minTop) * (1 - _animationController.value),
child: child,
);
},
child: Dot(),
);
},
);
Overlay.of(context).insert(entry);
await _animationController.forward(from: 0);
entry.remove();
}
#override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
SizedBox(height: 32),
ItemFader(key: keys[0], child: StepNumber(number: widget.number)),
ItemFader(
key: keys[1],
child: StepQuestion(question: widget.question),
),
Spacer(),
...widget.answers.map((String answer) {
int answerIndex = widget.answers.indexOf(answer);
int keyIndex = answerIndex + 2;
return ItemFader(
key: keys[keyIndex],
child: OptionItem(
name: answer,
onTap: (offset) => onTap(keyIndex, offset),
showDot: selectedOptionKeyIndex != keyIndex,
),
);
}),
SizedBox(height: 64),
],
);
}
void onTap(int keyIndex, Offset offset) async {
for (GlobalKey<_ItemFaderState> key in keys) {
await Future.delayed(Duration(milliseconds: 40));
key.currentState.hide();
if (keys.indexOf(key) == keyIndex) {
setState(() => selectedOptionKeyIndex = keyIndex);
animateDot(offset).then((_) => widget.onOptionSelected());
}
}
}
void onInit() async {
for (GlobalKey<_ItemFaderState> key in keys) {
await Future.delayed(Duration(milliseconds: 40));
key.currentState.show();
}
}
}
class StepNumber extends StatelessWidget {
final int number;
const StepNumber({Key key, #required this.number}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 64, right: 16),
child: Text(
'0$number',
style: TextStyle(
fontSize: 64,
fontWeight: FontWeight.bold,
color: Colors.white.withOpacity(0.5),
),
),
);
}
}
class StepQuestion extends StatelessWidget {
final String question;
const StepQuestion({Key key, #required this.question}) : super(key: key);
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(left: 64, right: 16),
child: Text(
question,
style: TextStyle(fontSize: 24),
),
);
}
}
class OptionItem extends StatefulWidget {
final String name;
final void Function(Offset dotOffset) onTap;
final bool showDot;
const OptionItem(
{Key key, #required this.name, #required this.onTap, this.showDot = true})
: super(key: key);
#override
_OptionItemState createState() => _OptionItemState();
}
class _OptionItemState extends State<OptionItem> {
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
RenderBox object = context.findRenderObject();
Offset globalPosition = object.localToGlobal(Offset.zero);
widget.onTap(globalPosition);
},
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Row(
children: <Widget>[
SizedBox(width: 26),
Dot(visible: widget.showDot),
SizedBox(width: 26),
Expanded(
child: Text(
widget.name,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 26),
),
)
],
),
),
);
}
}
class ItemFader extends StatefulWidget {
final Widget child;
const ItemFader({Key key, #required this.child}) : super(key: key);
#override
_ItemFaderState createState() => _ItemFaderState();
}
class _ItemFaderState extends State<ItemFader>
with SingleTickerProviderStateMixin {
//1 means its below, -1 means its above
int position = 1;
AnimationController _animationController;
Animation _animation;
void show() {
setState(() => position = 1);
_animationController.forward();
}
void hide() {
setState(() => position = -1);
_animationController.reverse();
}
#override
void initState() {
super.initState();
_animationController = AnimationController(
vsync: this,
duration: Duration(milliseconds: 600),
);
_animation = CurvedAnimation(
parent: _animationController,
curve: Curves.easeInOut,
);
}
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _animation,
builder: (context, child) {
return Transform.translate(
offset: Offset(0, 64 * position * (1 - _animation.value)),
child: Opacity(
opacity: _animation.value,
child: child,
),
);
},
child: widget.child,
);
}
}
class Dot extends StatelessWidget {
final bool visible;
const Dot({Key key, this.visible = true}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
width: 12,
height: 12,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: visible ? Colors.white : Colors.transparent,
),
);
}
}
class ArrowIcons extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Positioned(
left: 8,
bottom: 0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: () {},
),
Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
child: IconButton(
color: Color.fromRGBO(120, 58, 183, 1),
icon: Icon(Icons.arrow_downward),
onPressed: () {},
),
),
],
),
);
}
}
class Plane extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Positioned(
left: 32.0 + 8,
top: 32,
child: RotatedBox(
quarterTurns: 2,
child: Icon(
Icons.airplanemode_active,
size: 64,
),
),
);
}
}
const backgroundDecoration = BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromRGBO(76, 61, 243, 1),
Color.fromRGBO(120, 58, 183, 1),
],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
);
Navigator push() and pop() could be what you are looking for if you want to open a new page, pass the particular questions data as arguments
Flutter Official Doc