Flutter UncontrolledProviderScope error with Riverpod - flutter

Here i have a simple animated dialog which with that i can show one screen into that. this screen into animated dialog sending request on appearing into dialog and can be receive data from server without any problem. but when i drag this dialog on top of screen to get full width and height i get this error:
This UncontrolledProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
in fact i think this screen send multiple request when appear into dialog and when its shows as a new screen instance
problem is
ref.read(profileProvider.notifier).send(
method: HTTP.POST,
endPoint: Server.$userProfile,
parameters: {
'uuid': '123',
},
);
into MyProfile class
Full source code:
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:my_app/core/service/server.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'core/service/repository/request_repository.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(
ProviderScope(child: MyApp()),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'test',
home: MyHome(),
);
}
}
class MyHome extends HookConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
GestureDetector(
onLongPress: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: "hi",
// barrierColor: Colors.black.withOpacity(0.2),
// transitionDuration: Duration(milliseconds: 500),
pageBuilder: (context, pAnim, sAnim) {
return const SafeArea(
child: FloatingDialog(
previewType: PreviewDialogsType.profile,
));
},
transitionBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.reverse) {
return FadeTransition(
opacity: Tween(begin: 0.0, end: 0.0).animate(pAnim),
child: child,
);
} else {
return FadeTransition(
opacity: pAnim,
child: child,
);
}
},
);
},
child: Container(
width: double.infinity,
height: 50.0,
color: Colors.indigoAccent,
child: const Text('LongPress please'),
),
),
],
),
);
}
}
enum PreviewDialogsType {
profile,
}
class FloatingDialog extends StatefulWidget {
final PreviewDialogsType previewType;
const FloatingDialog({super.key, required this.previewType});
#override
_FloatingDialogState createState() => _FloatingDialogState();
}
class _FloatingDialogState extends State<FloatingDialog> with TickerProviderStateMixin {
late double _dragStartYPosition;
late double _dialogYOffset;
late AnimationController _returnBackController;
late Animation<double> _dialogAnimation;
#override
void initState() {
super.initState();
_dialogYOffset = 0.0;
_returnBackController = AnimationController(vsync: this, duration: const Duration(milliseconds: 1300))
..addListener(() {
setState(() {
_dialogYOffset = _dialogAnimation.value;
});
});
}
#override
void dispose() {
_returnBackController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
Widget myContents = PreviewDialog(
type: widget.previewType,
);
return Padding(
padding: const EdgeInsets.only(
top: 100.0,
bottom: 10.0,
left: 16.0,
right: 16.0,
),
child: Transform.translate(
offset: Offset(0.0, _dialogYOffset),
child: Column(
children: <Widget>[
const Icon(
Icons.keyboard_arrow_up,
color: Colors.white,
size: 30.0,
),
Expanded(
child: GestureDetector(
onVerticalDragStart: (dragStartDetails) {
_dragStartYPosition = dragStartDetails.globalPosition.dy;
},
onVerticalDragUpdate: (dragUpdateDetails) {
setState(() {
_dialogYOffset = (dragUpdateDetails.globalPosition.dy) - _dragStartYPosition;
});
if (_dialogYOffset < -130) {
Navigator.of(context).pop();
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, pAnim, sAnim) => myContents,
transitionDuration: const Duration(milliseconds: 500),
transitionsBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.forward) {
return ScaleTransition(
scale: Tween(begin: 0.8, end: 1.0)
.animate(CurvedAnimation(parent: pAnim, curve: Curves.elasticOut)),
child: child,
);
} else {
return child;
}
}),
);
}
},
onVerticalDragEnd: (dragEndDetails) {
_dialogAnimation = Tween(begin: _dialogYOffset, end: 0.0)
.animate(CurvedAnimation(parent: _returnBackController, curve: Curves.elasticOut));
_returnBackController.forward(from: _dialogYOffset);
_returnBackController.forward(from: 0.0);
},
child: myContents,
),
),
],
),
),
);
}
}
class PreviewDialog extends StatefulWidget {
final PreviewDialogsType type;
final String? uuid;
const PreviewDialog({Key? key, required this.type, this.uuid}) : super(key: key);
#override
State<PreviewDialog> createState() => _PreviewDialogState();
}
class _PreviewDialogState extends State<PreviewDialog> {
late ScrollController scrollController;
#override
void initState() {
super.initState();
scrollController = ScrollController();
}
#override
Widget build(BuildContext context) {
return Directionality(
textDirection: TextDirection.rtl,
child: ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: Scaffold(
body: MyProfile(),
),
),
);
}
}
class MyProfile extends HookConsumerWidget {
#override
Widget build(BuildContext context, WidgetRef ref) {
useEffect(() {
ref.read(profileProvider.notifier).send(
method: HTTP.POST,
endPoint: Server.$userProfile,
parameters: {
'uuid': '123',
},
);
return () {};
}, []);
return SafeArea(
child: Scaffold(
body: Container(
width: double.infinity,
height:double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ref.watch(profileProvider).when(
idle: () => const SizedBox(),
loading: () => const CircularProgressIndicator(),
success: (success) {
return const Text('successful');
},
error: (error, stackTrace) {
return Text('error');
},
)
],
),
),
),
);
}
}

Related

Persistent Navigation Bar only in some pages

Stackoverflowers!
I'm using an BottomAppBar inside the bottomNavigationBar section of the Scaffold. The problem is that it doesn't persists while I'm navigating. I used the persistent_bottom_nav_bar plugin, but it doesn't work with my custom navigation bar because it has a ripple animation in one button and a bottomSheet that is over the keyboard.
home_page.dart
This file has the CustomNavigationBar and the main pages for each item on it.
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
NavigationProvider? navigationProvider;
AnimationController? rippleController;
AnimationController? scaleController;
Animation<double>? rippleAnimation;
Animation<double>? scaleAnimation;
#override
void initState() {
super.initState();
rippleController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500));
scaleController = AnimationController(
vsync: this, duration: const Duration(milliseconds: 500))
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
scaleController!.reverse();
Navigator.push(
context,
PageTransition(
type: PageTransitionType.bottomToTop,
child: pages.elementAt(2),
childCurrent: widget,
fullscreenDialog: true,
)).whenComplete(() => setState(() {
buttonColor = Colors.black;
}));
}
});
rippleAnimation =
Tween<double>(begin: 80.0, end: 90.0).animate(rippleController!)
..addStatusListener((status) {
if (status == AnimationStatus.completed) {
rippleController!.reverse();
} else if (status == AnimationStatus.dismissed) {
rippleController!.forward();
}
});
scaleAnimation =
Tween<double>(begin: 1.0, end: 30.0).animate(scaleController!);
rippleController!.forward();
}
#override
void dispose() {
rippleController!.dispose();
scaleController!.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
navigationProvider = Provider.of<NavigationProvider>(context);
return Scaffold(
body:
pages.elementAt(navigationProvider!.bottomNavigationBarSelectedIndex),
bottomNavigationBar: CustomNavigationBar(
rippleController: rippleController,
scaleController: scaleController,
rippleAnimation: rippleAnimation,
scaleAnimation: scaleAnimation),
);
}
}
custom_navigation_bar.dart
This file contains the properties of the CustomNavigationBar.
class CustomNavigationBar extends StatefulWidget {
const CustomNavigationBar({
super.key,
this.rippleController,
this.scaleController,
this.rippleAnimation,
this.scaleAnimation,
});
final AnimationController? rippleController;
final AnimationController? scaleController;
final Animation<double>? rippleAnimation;
final Animation<double>? scaleAnimation;
#override
State<CustomNavigationBar> createState() => _CustomNavigationBarState();
}
class _CustomNavigationBarState extends State<CustomNavigationBar> {
#override
Widget build(BuildContext context) {
final navigationProvider = Provider.of<NavigationProvider>(context);
return BottomAppBar(
child: IconTheme(
data: const IconThemeData(color: Colors.black, size: 36),
child: Padding(
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5),
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
direction: Axis.vertical,
children: [
IconButton(
icon: ...,
padding: ...,
constraints: ...,
onPressed: () {
//Here I change the selected index with Provider.
...
},
),
Text(
title,
style: ...,
),
],
),
const Spacer(),
Wrap(...),
const Spacer(),
InkWell(
onTap: () {
setState(
() {
//Executes the ripple animation.
widget.scaleController!.forward();
},
);
},
child: AnimatedBuilder(
animation: widget.scaleAnimation!,
builder: (context, child) => Transform.scale(
scale: widget.scaleAnimation!.value,
child: Container(
width: 50,
height: 50,
margin: const EdgeInsets.all(10),
decoration: const BoxDecoration(
shape: BoxShape.circle, color: Colors.blue),
child: Icon(Icons.add,
color: widget.scaleAnimation!.value == 1.0
? Colors.white
: Colors.blue),
),
),
),
),
const Spacer(),
Wrap(...),
const Spacer(),
Wrap(...),
],
),
),
),
);
}
}
As you can see, I use Provider to manage the state of the CustomNavigationBar when it changes the index.
Example of what I want:
This app is Splitwise and it has some pages with the navigation bar and others without it. That ripple animation is similar to mine. Also the bottom sheet has the same effect in my app.
I'll wait for all your suggestions, thanks!

How to add onPressed to multiple FloatingActionButton in flutter

I have an example of a FloatingActionButton working multiple but I don't know how to add it onPressed to it.
I found on the form of the following topic:
https://stackoverflow.com/a/46480722/14451514
In the example there are three icons I need to know how I can onPressed it how I do that?
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _controller;
static const List<IconData> icons = const [ Icons.sms, Icons.mail, Icons.phone ];
#override
void initState() {
_controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
}
Widget build(BuildContext context) {
Color backgroundColor = Theme.of(context).cardColor;
Color foregroundColor = Theme.of(context).accentColor;
return new Scaffold(
appBar: new AppBar(title: new Text('Speed Dial Example')),
floatingActionButton: new Column(
mainAxisSize: MainAxisSize.min,
children: new List.generate(icons.length, (int index) {
Widget child = new Container(
height: 70.0,
width: 56.0,
alignment: FractionalOffset.topCenter,
child: new ScaleTransition(
scale: new CurvedAnimation(
parent: _controller,
curve: new Interval(
0.0,
1.0 - index / icons.length / 2.0,
curve: Curves.easeOut
),
),
child: new FloatingActionButton(
heroTag: null,
backgroundColor: backgroundColor,
mini: true,
child: new Icon(icons[index], color: foregroundColor),
onPressed: () {},
),
),
);
return child;
}).toList()..add(
new FloatingActionButton(
heroTag: null,
child: new AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return new Transform(
transform: new Matrix4.rotationZ(_controller.value * 0.5 * math.pi),
alignment: FractionalOffset.center,
child: new Icon(_controller.isDismissed ? Icons.share : Icons.close),
);
},
),
onPressed: () {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
),
),
);
}
}
If anyone knows the solution to that problem please help me
I would suggest you to add a FAB Onpress button, use this github program.
Speed Dail Floating Action Bar
https://github.com/tiagojencmartins/unicornspeeddial
A List (Array) of functions can help you here, you have an index of the current item just get the function from List by index and call it onPress.
import 'package:flutter/material.dart';
import 'dart:math' as math;
void main() {
runApp(new MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
State createState() => new MyHomePageState();
}
class MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
AnimationController _controller;
static const List<IconData> icons = const [
Icons.sms,
Icons.mail,
Icons.phone
];
static method1() {
print('method 1');
}
static method2() {
print('method 2');
}
static method3() {
print('method 3');
}
List<Function> methods = [method1, method2, method3];
#override
void initState() {
_controller = new AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
}
Widget build(BuildContext context) {
Color backgroundColor = Theme.of(context).cardColor;
Color foregroundColor = Theme.of(context).accentColor;
return new Scaffold(
appBar: new AppBar(title: new Text('Speed Dial Example')),
floatingActionButton: new Column(
mainAxisSize: MainAxisSize.min,
children: new List.generate(icons.length, (int index) {
Widget child = new Container(
height: 70.0,
width: 56.0,
alignment: FractionalOffset.topCenter,
child: new ScaleTransition(
scale: new CurvedAnimation(
parent: _controller,
curve: new Interval(0.0, 1.0 - index / icons.length / 2.0,
curve: Curves.easeOut),
),
child: new FloatingActionButton(
heroTag: null,
backgroundColor: backgroundColor,
mini: true,
child: new Icon(icons[index], color: foregroundColor),
onPressed: () {
methods[index]();
},
),
),
);
return child;
}).toList()
..add(
new FloatingActionButton(
heroTag: null,
child: new AnimatedBuilder(
animation: _controller,
builder: (BuildContext context, Widget child) {
return new Transform(
transform: new Matrix4.rotationZ(
_controller.value * 0.5 * math.pi),
alignment: FractionalOffset.center,
child: new Icon(
_controller.isDismissed ? Icons.share : Icons.close),
);
},
),
onPressed: () {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
),
),
);
}
}
try this out
You need to extend your IconData list to a model that contains Function. It will look something like this:
class NewModel {
IconData iconData;
Function func;
}
And then:
static const List<NewModel> iconsWithFunc =
[
/* Your Items with OnPressed Functions */
];
After that you can use it easily:
child: new FloatingActionButton(
heroTag: null,
backgroundColor: backgroundColor,
mini: true,
child: new Icon(iconsWithFunc[index].iconData, color: foregroundColor),
// Use it in here.
onPressed: iconsWithFunc[index].func,
),

How to call setState (rebuild page), after pop of PopUpWindow?

I'm trying to update/rebuild a route beneath a popup window when the popup window is popped, using Navigator.pop(context). On the popup window the user can add something to a list, and the route beneath (the page), the added item shows in a ListView. So more specifically I need my ListView to be up to date with the actual list. But nothing I have tried yet, have worked.
As mentioned, I have already tried quite a few things, including:
didPopNext() (using RouteAware), changedExternalState (which I couldn't quite get the grasp of), trying to pass a function only containing a setState(() {}), and other things.
Hope somebody can help with how I can rebuild the ListView when the popup window is popped.
Thanks in advance.
This example should summarize my problem decently close (couldn't show you the actual code, because it's gotten way over 2.000 lines, but the core elements of the problem should be here):
import 'package:flutter/material.dart';
void main() => runApp(new MaterialApp(
home: MyPage()));
class PopupLayout extends ModalRoute<void> {
#override
Duration get transitionDuration => Duration(milliseconds: 300);
#override
bool get opaque => false;
#override
bool get barrierDismissible => false;
#override
bool get semanticsDismissible => true;
#override
Color get barrierColor =>
bgColor == null ? Colors.black.withOpacity(0.5) : bgColor;
#override
String get barrierLabel => null;
#override
bool get maintainState => false;
double top;
double bottom;
double left;
double right;
Color bgColor;
final Widget child;
PopupLayout(
{Key key,
this.bgColor,
#required this.child,
this.top,
this.bottom,
this.left,
this.right});
#override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
if (top == null) this.top = 10;
if (bottom == null) this.bottom = 20;
if (left == null) this.left = 20;
if (right == null) this.right = 20;
return GestureDetector(
onTap: () {},
child: Material(
type: MaterialType.transparency,
child: _buildOverlayContent(context),
),
);
}
Widget _buildOverlayContent(BuildContext context) {
return Container(
margin: EdgeInsets.only(
bottom: this.bottom,
left: this.left,
right: this.right,
top: this.top),
child: child,
);
}
#override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: animation,
child: child,
),
);
}
}
class PopupContent extends StatefulWidget {
final Widget content;
PopupContent({
Key key,
this.content,
}) : super(key: key);
_PopupContentState createState() => _PopupContentState();
}
class _PopupContentState extends State<PopupContent> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
child: widget.content,
);
}
}
popupContent(BuildContext context, Widget widget,
{BuildContext popupContext}) {
Navigator.push(
context,
PopupLayout(
top: 120,
left: 20,
right: 20,
bottom: 120,
child: PopupContent(
content: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: widget,
),
),
),
);
}
Widget popupWidget(BuildContext context) {
return new Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("This is a popupPage"),
FlatButton(
onPressed: () {
list.add("Irrelevant");
Navigator.pop(context); //The rebuild of the page underneath, needs to be called when this pops
},
child: Text("Press me to change text on home page"),
),
]
),
);
}
List list = [];
class MyPage extends StatefulWidget {
#override
createState() => MyPageState();
}
class MyPageState extends State<MyPage> {
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Container(
width: 300,
height: 400,
child: ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Center(
child: Text(index.toString()),
);
},
),
),
),
Center(
child: FlatButton(
onPressed: () {
popupContent(context, popupWidget(context));
},
child: Text("Press me for popup window"),
),
),
Center(
child: FlatButton(
onPressed: () {
setState(() {});
},
child: Text("Press me to rebuild page (setState)"),
),
),
]
),
);
}
}
You can add a function in MyPage and pass it to your popUpWidget. Code:
import 'package:flutter/material.dart';
void main() => runApp(new MaterialApp(home: MyPage()));
class PopupLayout extends ModalRoute<void> {
#override
Duration get transitionDuration => Duration(milliseconds: 300);
#override
bool get opaque => false;
#override
bool get barrierDismissible => false;
#override
bool get semanticsDismissible => true;
#override
Color get barrierColor =>
bgColor == null ? Colors.black.withOpacity(0.5) : bgColor;
#override
String get barrierLabel => null;
#override
bool get maintainState => false;
double top;
double bottom;
double left;
double right;
Color bgColor;
final Widget child;
PopupLayout(
{Key key,
this.bgColor,
#required this.child,
this.top,
this.bottom,
this.left,
this.right});
#override
Widget buildPage(
BuildContext context,
Animation<double> animation,
Animation<double> secondaryAnimation,
) {
if (top == null) this.top = 10;
if (bottom == null) this.bottom = 20;
if (left == null) this.left = 20;
if (right == null) this.right = 20;
return GestureDetector(
onTap: () {},
child: Material(
type: MaterialType.transparency,
child: _buildOverlayContent(context),
),
);
}
Widget _buildOverlayContent(BuildContext context) {
return Container(
margin: EdgeInsets.only(
bottom: this.bottom,
left: this.left,
right: this.right,
top: this.top),
child: child,
);
}
#override
Widget buildTransitions(BuildContext context, Animation<double> animation,
Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(
opacity: animation,
child: ScaleTransition(
scale: animation,
child: child,
),
);
}
}
class PopupContent extends StatefulWidget {
final Widget content;
PopupContent({
Key key,
this.content,
}) : super(key: key);
_PopupContentState createState() => _PopupContentState();
}
class _PopupContentState extends State<PopupContent> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
child: widget.content,
);
}
}
popupContent(BuildContext context, Widget widget, {BuildContext popupContext}) {
Navigator.push(
context,
PopupLayout(
top: 120,
left: 20,
right: 20,
bottom: 120,
child: PopupContent(
content: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomInset: false,
body: widget,
),
),
),
);
}
Widget popupWidget(BuildContext context, Function callback) {
//Pass The Function Here //////////////////////
return new Container(
child:
Column(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Text("This is a popupPage"),
FlatButton(
onPressed: () {
list.add("Irrelevant");
callback(); // Call It Here /////////////////////////
Navigator.pop(
context); //The rebuild of the page underneath, needs to be called when this pops
},
child: Text("Press me to change text on home page"),
),
]),
);
}
List list = [];
class MyPage extends StatefulWidget {
#override
createState() => MyPageState();
}
class MyPageState extends State<MyPage> {
//The Calback Function //////////////////////////
void callback() {
setState(() {});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Center(
child: Container(
width: 300,
height: 400,
child: ListView.builder(
itemCount: list.length,
itemBuilder: (BuildContext context, int index) {
return Center(
child: Text(index.toString()),
);
},
),
),
),
Center(
child: FlatButton(
onPressed: () {
popupContent(context, popupWidget(context, this.callback)); //Passing the Function here ////////////
},
child: Text("Press me for popup window"),
),
),
Center(
child: FlatButton(
onPressed: () {
setState(() {});
},
child: Text("Press me to rebuild page (setState)"),
),
),
]),
);
}
}

Flutter animate reverse effect on FadeTransition

in this simple code, i try to show and hide barrier on top of widgets,showing this barrier can be have with animation, but when i try to close and hide that, controller.reverse() doesn't have any animation to hide
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(
home: BarrierEffect(),
));
class BarrierEffect extends StatefulWidget {
#override
State<BarrierEffect> createState() => _BarrierEffect();
}
class _BarrierEffect extends State<BarrierEffect> with TickerProviderStateMixin {
var isShownBarrier = false;
AnimationController controller;
Animation<double> animation;
#override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(milliseconds: 1000), vsync: this);
animation = CurvedAnimation(parent: controller, curve: Curves.easeIn);
animation.addStatusListener((status) {
if (status == AnimationStatus.completed) {
controller.reverse();
setState(() {
isShownBarrier = false;
});
} else if (status == AnimationStatus.dismissed) {
controller.forward();
setState(() {
isShownBarrier = true;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Stack(
children: <Widget>[
Center(
child: RaisedButton(
color: Colors.white,
child: Text('show barrier'),
onPressed: () => controller.forward(),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0))),
),
Visibility(
visible: isShownBarrier ? true : false,
child: FadeTransition(
opacity: animation,
child: Container(
color: Colors.black.withOpacity(0.5),
child: Center(child: Text('test')),
),
),
)
],
),
),
);
}
}
Is this what you are looking for?
Full code:
void main() => runApp(MaterialApp(home: BarrierEffect()));
class BarrierEffect extends StatefulWidget {
#override
State<BarrierEffect> createState() => _BarrierEffect();
}
class _BarrierEffect extends State<BarrierEffect> with TickerProviderStateMixin {
AnimationController controller;
#override
void initState() {
super.initState();
controller = AnimationController(duration: const Duration(milliseconds: 2000), vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnimatedBuilder(
animation: controller,
builder: (_, child) {
return Stack(
children: <Widget>[
Center(
child: RaisedButton(
child: Text('Show Barrier'),
onPressed: () => controller.repeat(reverse: true),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(50.0)),
),
),
Visibility(
visible: controller.value != 0,
child: Opacity(
opacity: controller.value,
child: Container(
color: Colors.black.withOpacity(0.9),
child: Center(child: Text('My Barrier', style: TextStyle(color: Colors.white))),
),
),
)
],
);
},
),
);
}
}

Flutter adding more options for dialogs

is any solution to make drag and drop dialogs in flutter? for example after showing dialog in center of screen i would like to drag it to top of screen to make fullscreen dialog over current cover, for example this code is simple implementation to show dialog and i'm not sure, how can i do that
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(title: 'Flutter Demo', theme: ThemeData(), home: Page());
}
}
class Page extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton.icon(
onPressed: () {
showDialog(
context: context,
builder: (_) => FunkyOverlay(),
);
},
icon: Icon(Icons.message),
label: Text("PopUp!")),
),
);
}
}
class FunkyOverlay extends StatefulWidget {
#override
State<StatefulWidget> createState() => FunkyOverlayState();
}
class FunkyOverlayState extends State<FunkyOverlay>
with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> scaleAnimation;
#override
void initState() {
super.initState();
controller =
AnimationController(vsync: this, duration: Duration(milliseconds: 450));
scaleAnimation =
CurvedAnimation(parent: controller, curve: Curves.elasticInOut);
controller.addListener(() {
setState(() {});
});
controller.forward();
}
#override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: ScaleTransition(
scale: scaleAnimation,
child: Container(
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0))),
child: Padding(
padding: const EdgeInsets.all(50.0),
child: Text("Well hello there!"),
),
),
),
),
);
}
}
This is one way to do it ,
import 'package:flutter/material.dart';
main() {
runApp(MaterialApp(
theme: ThemeData(
primarySwatch: Colors.indigo,
),
home: App(),
));
}
class App extends StatefulWidget {
#override
State<App> createState() => _AppState();
}
class _AppState extends State<App> {
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.open_in_new),
onPressed: () {
showGeneralDialog(
context: context,
barrierDismissible: true,
barrierLabel: "hi",
barrierColor: Colors.black.withOpacity(0.2),
transitionDuration: Duration(milliseconds: 500),
pageBuilder: (context, pAnim, sAnim) {
return SafeArea(child: FloatingDialog());
},
transitionBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.reverse) {
return FadeTransition(
opacity: Tween(begin: 0.0, end: 0.0).animate(pAnim),
child: child,
);
} else {
return FadeTransition(
opacity: pAnim,
child: child,
);
}
},
);
},
),
);
}
}
class FloatingDialog extends StatefulWidget {
#override
_FloatingDialogState createState() => _FloatingDialogState();
}
class _FloatingDialogState extends State<FloatingDialog>
with TickerProviderStateMixin {
double _dragStartYPosition;
double _dialogYOffset;
Widget myContents = MyScaffold();
AnimationController _returnBackController;
Animation<double> _dialogAnimation;
#override
void initState() {
super.initState();
_dialogYOffset = 0.0;
_returnBackController =
AnimationController(vsync: this, duration: Duration(milliseconds: 1300))
..addListener(() {
setState(() {
_dialogYOffset = _dialogAnimation.value;
print(_dialogYOffset);
});
});
}
#override
void dispose() {
_returnBackController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
top: 100.0,
bottom: 10.0,
left: 10.0,
right: 10.0,
),
child: Transform.translate(
offset: Offset(0.0, _dialogYOffset),
child: Column(
children: <Widget>[
Icon(
Icons.keyboard_arrow_up,
color: Colors.white,
),
Expanded(
child: GestureDetector(
onVerticalDragStart: (dragStartDetails) {
_dragStartYPosition = dragStartDetails.globalPosition.dy;
print(dragStartDetails.globalPosition);
},
onVerticalDragUpdate: (dragUpdateDetails) {
setState(() {
_dialogYOffset = (dragUpdateDetails.globalPosition.dy) -
_dragStartYPosition;
});
print(_dialogYOffset);
if (_dialogYOffset < -90.0) {
Navigator.of(context).pop();
Navigator.of(context).push(
PageRouteBuilder(
pageBuilder: (context, pAnim, sAnim) => myContents,
transitionDuration: Duration(milliseconds: 500),
transitionsBuilder: (context, pAnim, sAnim, child) {
if (pAnim.status == AnimationStatus.forward) {
return ScaleTransition(
scale: Tween(begin: 0.8, end: 1.0).animate(
CurvedAnimation(
parent: pAnim,
curve: Curves.elasticOut)),
child: child,
);
} else {
return FadeTransition(
opacity: pAnim,
child: child,
);
}
}),
);
}
},
onVerticalDragEnd: (dragEndDetails) {
_dialogAnimation = Tween(begin: _dialogYOffset, end: 0.0)
.animate(CurvedAnimation(
parent: _returnBackController,
curve: Curves.elasticOut));
_returnBackController.forward(from: _dialogYOffset);
_returnBackController.forward(from: 0.0);
},
child: myContents,
),
),
],
),
),
);
}
}
class MyScaffold extends StatelessWidget {
const MyScaffold({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Channels"),
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => Scaffold(
appBar: AppBar(),
body: Placeholder(),
),
),
);
},
),
),
);
}
}
Output:
You can try this.
void main() => runApp(MaterialApp(home: HomePage()));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
bool _shown = false;
double _topOffset = 20, _dialogHeight = 400;
Duration _duration = Duration(milliseconds: 400);
Offset _offset, _initialOffset;
#override
void didChangeDependencies() {
super.didChangeDependencies();
var size = MediaQuery.of(context).size;
_offset = Offset(size.width, (size.height - _dialogHeight) / 2);
_initialOffset = _offset;
}
#override
Widget build(BuildContext context) {
var appBarColor = Colors.blue[800];
return Scaffold(
floatingActionButton: FloatingActionButton(onPressed: () => setState(() => _shown = !_shown)),
body: SizedBox.expand(
child: Stack(
children: <Widget>[
Container(
color: appBarColor,
child: SafeArea(
bottom: false,
child: Align(
child: Column(
children: <Widget>[
MyAppBar(
title: "Image",
color: appBarColor,
icon: Icons.home,
onPressed: () {},
),
Expanded(child: Image.asset("assets/images/landscape.jpeg", fit: BoxFit.cover)),
],
),
),
),
),
AnimatedOpacity(
opacity: _shown ? 1 : 0,
duration: _duration,
child: Material(
elevation: 8,
color: Colors.grey[900].withOpacity(0.5),
child: _shown
? GestureDetector(
onTap: () => setState(() => _shown = !_shown),
child: Container(color: Colors.transparent, child: SizedBox.expand()),
)
: SizedBox.shrink(),
),
),
// this shows our dialog
Positioned(
top: _offset.dy,
left: 10,
right: 10,
height: _shown ? null : 0,
child: AnimatedOpacity(
duration: _duration,
opacity: _shown ? 1 : 0,
child: GestureDetector(
onPanUpdate: (details) => setState(() => _offset += details.delta),
onPanEnd: (details) {
// when tap is lifted and current y position is less than set _offset, navigate to the next page
if (_offset.dy < _topOffset) {
Navigator.push(
context,
PageRouteBuilder(
pageBuilder: (context, anim1, anim2) => Screen2(),
transitionDuration: _duration,
transitionsBuilder: (context, anim1, anim2, child) {
bool isForward = anim1.status == AnimationStatus.forward;
Tween<double> tween = Tween(begin: isForward ? 0.9 : 0.5, end: 1);
return ScaleTransition(
scale: tween.animate(
CurvedAnimation(
parent: anim1,
curve: isForward ? Curves.bounceOut : Curves.easeOut,
),
),
child: child,
);
},
),
).then((_) {
_offset = _initialOffset;
});
}
// make the dialog come back to the original position
else {
Timer.periodic(Duration(milliseconds: 5), (timer) {
if (_offset.dy < _initialOffset.dy - _topOffset) {
_offset = Offset(_offset.dx, _offset.dy + 15);
setState(() {});
} else if (_offset.dy > _initialOffset.dy + _topOffset) {
_offset = Offset(_offset.dx, _offset.dy - 15);
setState(() {});
} else
timer.cancel();
});
}
},
child: Column(
children: <Widget>[
Icon(Icons.keyboard_arrow_up, color: Colors.white, size: 32),
Hero(
tag: "MyTag",
child: SizedBox(
height: _dialogHeight, // makes sure we don't exceed than our specified height
child: SingleChildScrollView(child: CommonWidget(appBar: MyAppBar(title: "FlutterLogo", color: Colors.orange))),
),
),
],
),
),
),
),
],
),
),
);
}
}
// this app bar is used in 1st and 2nd screen
class MyAppBar extends StatelessWidget {
final String title;
final Color color;
final IconData icon;
final VoidCallback onPressed;
const MyAppBar({Key key, #required this.title, #required this.color, this.icon, this.onPressed}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: kToolbarHeight,
color: color,
width: double.maxFinite,
alignment: Alignment.centerLeft,
child: Row(
children: <Widget>[
icon != null ? IconButton(icon: Icon(icon), onPressed: onPressed, color: Colors.white,) : SizedBox(width: 16),
Text(
title,
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white),
),
],
),
);
}
}
// this is the one which is shown in both Dialog and Screen2
class CommonWidget extends StatelessWidget {
final bool isFullscreen;
final Widget appBar;
const CommonWidget({Key key, this.isFullscreen = false, this.appBar}) : super(key: key);
#override
Widget build(BuildContext context) {
var child = Container(
width: double.maxFinite,
color: Colors.blue,
child: FlutterLogo(size: 300, colors: Colors.orange),
);
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
appBar,
isFullscreen ? Expanded(child: child) : child,
],
);
}
}
class Screen2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
var appBarColor = Colors.orange;
return Scaffold(
body: Container(
color: appBarColor,
child: SafeArea(
bottom: false,
child: CommonWidget(
isFullscreen: true,
appBar: MyAppBar(
title: "FlutterLogo",
color: appBarColor,
icon: Icons.arrow_back,
onPressed: () => Navigator.pop(context),
),
),
),
),
);
}
}