How to create interactive flowchart in flutter - flutter

I want to create a flutter UI where there are some shapes like square, rectangle, circle, arrow. And I must be able to drag and drop them at the centre and add text to it and connect them. I have just started with flutter so I am not sure how to do this. Can anyone please help me?

Use Draggable class
Example:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const MyStatefulWidget(),
),
);
}
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int acceptedData = 0;
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Draggable<int>(
// Data is the value this Draggable stores.
data: 10,
feedback: Container(
color: Colors.deepOrange,
height: 100,
width: 100,
child: const Icon(Icons.directions_run),
),
childWhenDragging: Container(
height: 100.0,
width: 100.0,
color: Colors.pinkAccent,
child: const Center(
child: Text('Child When Dragging'),
),
),
child: Container(
height: 100.0,
width: 100.0,
color: Colors.lightGreenAccent,
child: const Center(
child: Text('Draggable'),
),
),
),
DragTarget<int>(
builder: (
BuildContext context,
List<dynamic> accepted,
List<dynamic> rejected,
) {
return Container(
height: 100.0,
width: 100.0,
color: Colors.cyan,
child: Center(
child: Text('Value is updated to: $acceptedData'),
),
);
},
onAccept: (int data) {
setState(() {
acceptedData += data;
});
},
),
],
);
}
}

Related

How to customize the Animation of the Circular CountDownTimer

I want to customize the CircularCountdownTimer so that you can run it without a limited duration. After one hour the ring should be completely filled and the animation should start again from 0 after 1 hour. Does anyone know how to do this?
Here is my code
import 'package:circular_countdown_timer/circular_countdown_timer.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
CountDownController controller = CountDownController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularCountDownTimer(
width: 300,
height: 300,
duration: 60,
fillColor: Colors.blue,
ringColor: Colors.blue.withOpacity(0.25),
autoStart: false,
controller: controller,
),
const SizedBox(
height: 100,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
TextButton(
onPressed: () {
controller.start();
},
child: const Text("Start"),
),
TextButton(
onPressed: () {
controller.pause();
},
child: const Text("Pause"),
),
],
),
],
),
),
);
}
}
You can use onComplete to restart the animation.
CircularCountDownTimer(
width: 300,
height: 300,
duration: 60, // it is on seconds,
fillColor: Colors.blue,
ringColor: Colors.blue.withOpacity(0.25),
autoStart: false,
controller: controller,
onComplete: () {
controller.restart();
},
),

Nesting scaffolds in flutter to implement a slider

I'd like to use a custom slider instead of Material Design drawer.
The default drawer does not occupy any space in the scaffold and is pushed over the layout. I want a NavBar just like the desktop version of this site.
Therefore, I nested a scaffold inside another one to make navigation possible inside the inner scaffold.
Here is my code:
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var show = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Multi Scaffold',
home: Scaffold(
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.menu),
onPressed: () {
setState(() {
show = !show;
});
},
),
title: const Text("App"),
),
body: InsideWidget(show: show),
),
);
}
}
class InsideWidget extends StatelessWidget {
const InsideWidget({
Key? key,
required this.show,
}) : super(key: key);
final bool show;
#override
Widget build(BuildContext context) {
var w = MediaQuery.of(context).size.width;
var h = MediaQuery.of(context).size.height;
return Row(
children: [
show
? SizedBox(
width: 0.2 * w,
height: h,
child: Drawer(
child: Container(
decoration: BoxDecoration(boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.5),
spreadRadius: 5,
blurRadius: 7,
offset: const Offset(0, 3),
)
]),
child: ListView(
children: const [
DrawerHeader(child: Text("Iman")),
ListTile(
leading: Icon(Icons.ac_unit),
title: Text("Home"),
),
Divider(),
ListTile(
leading: Icon(Icons.vertical_distribute_rounded),
title: Text("Home3"),
),
],
),
)),
)
: Container(),
SizedBox(
width: show ? 0.8 * w : w,
height: h,
child: const Scaffold(
backgroundColor: Colors.yellow,
body:
SizedBox(width: 100, child: Center(child: Text("Content")))),
),
],
);
}
}
As of Flutter docs, nesting scaffolds is not recommended.
I wonder if this is the best practice or whether a better way to implement this behaviour exists or not.

Bounce Dismissible for helping the user

So we have a Dismissible for confirming/denying a item.
However we have some users that are trying to click/tap on the item.
Our UX team suggested that we then "bounce" the item to show that they have to swipe (and reveal the action fields).
But I don't see any option to do so.
Does anybody have a suggestion what might work for this?
The code I have for now is shown below:
Dismissible(
key: const ValueKey(0),
direction: DismissDirection.horizontal,
child: Container(
margin: EdgeInsets.symmetric(horizontal: 3, vertical: 3),
child: card(),
),
confirmDismiss: (direction) async {
var newStatus = direction == DismissDirection.startToEnd
? OkNokNvt.OK
: OkNokNvt.NOK;
_changeStatus(newStatus);
return false;
},
background: ok(),
secondaryBackground: nok(),
),
The Dismissable doesn't seeem to have this functionality.
Instead, you could use the flutter_slidable package.
Here, you can programmatically open the underlying actions by calling Slideable.of(context)?.open(). No fancy bounce-animation though.
Here's the code:
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bouncing Widget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Slidable(
key: const Key('key'),
actionPane: const SlidableDrawerActionPane(),
actionExtentRatio: 0.25,
child: Builder(
builder: (context) => GestureDetector(
onTap: () {
Slidable.of(context)
?.open(actionType: SlideActionType.primary);
},
child: Container(
color: Colors.grey,
height: 50,
child: const Center(child: Text('Tap me')),
),
),
),
actions: [
IconSlideAction(
caption: 'Delete',
color: Colors.red,
icon: Icons.delete,
onTap: () => print('remove me from list'),
),
],
dismissal: SlidableDismissal(
onDismissed: (_) => print('remove me from list'),
dragDismissible: true,
child: const SlidableDrawerDismissal(),
),
),
],
),
),
);
}
}
Here is my minimal example which does what you are looking for.
Basically, the GestureDetector onTap callback triggers the animation which has a bouncing-like effect by using a sin function on the _animation.value. The behaviour can be tweeked by changing the parameters cyclesPerAnimation and bounceOffset.
Simply put your Dismissible in the place of the Container and you should be good to go.
environment:
sdk: ">=2.12.0 <3.0.0"
import 'dart:math';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark(),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
late final AnimationController _animation = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
Offset _bounceOffset(double animationValue) {
const cyclesPerAnimation = 2;
const bounceOffset = 10;
return Offset(
0,
sin(animationValue * pi * 2 * cyclesPerAnimation) * bounceOffset,
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Bouncing Widget Example'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedBuilder(
animation: _animation,
builder: (context, widget) => Transform.translate(
offset: _bounceOffset(_animation.value),
child: GestureDetector(
onTap: () {
_animation.reset();
_animation.forward();
},
child: Container(
color: Colors.grey,
height: 50,
width: 200,
child: const Center(child: Text('Tap to bounce')),
),
),
),
),
],
),
),
);
}
}

Flutter: how can I implement an animated Container from left to right?

I implement a Room Chat Screen and inside it an animated Container move from left to right and start a again after finish, could someone inform me how to implement it
You need looping animate container, then you can try some Marquee package, such as fast_marquee:
Marquee(
text: 'Some sample text that takes some space.',
style: TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),
velocity: 100,
blankSpace: 10,
startPadding: 10,
reverse: true,
bounce: true,
startAfter: const Duration(seconds: 2),
pauseAfterRound: const Duration(seconds: 1),
numberOfRounds: 5,
showFadingOnlyWhenScrolling: false,
fadingEdgeStartFraction: 0.05,
fadingEdgeEndFraction: 0.05,
curve: Curves.easeInOut,
)
OR
try AnimatedPositioned:
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
static const String _title = 'Flutter Code Sample';
#override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: Scaffold(
appBar: AppBar(title: const Text(_title)),
body: const Center(
child: MyStatefulWidget(),
),
),
);
}
}
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool selected = false;
#override
Widget build(BuildContext context) {
return SizedBox(
width: 200,
height: 350,
child: Stack(
children: <Widget>[
AnimatedPositioned(
width: selected ? 200.0 : 50.0,
height: selected ? 50.0 : 200.0,
top: selected ? 50.0 : 150.0,
duration: const Duration(seconds: 2),
curve: Curves.fastOutSlowIn,
child: GestureDetector(
onTap: () {
setState(() {
selected = !selected;
});
},
child: Container(
color: Colors.blue,
child: const Center(child: Text('Tap me')),
),
),
),
],
),
);
}
}

How to update Draggable feedback widget while dragging?

I'm trying to make a game where I need to be able to click on a button while dragging a widget and that button should render som changes to the feedback widget that the user is currently dragging. The childWhenDragging updates just fine but the feedback widget doesn't update during the drag. Is there any way to achieve this?
This is a basic example to recreate it.
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Draggable Test',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int counter;
#override
void initState() {
this.counter = 0;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Draggable Test'),
),
body: Column(
children: <Widget>[
Draggable(
child: Container(
color: Colors.red,
width: 100,
height: 100,
child: Text(counter.toString()),
),
feedback: Container(
color: Colors.red,
width: 100,
height: 100,
child: Text(counter.toString()),
),
childWhenDragging: Container(
color: Colors.red,
width: 100,
height: 100,
child: Text(counter.toString()),
),
),
RaisedButton(
onPressed: () {
setState(() {
counter += 1;
});
},
child: Text("plus"),
)
],
),
);
}
}
I expect the feedback widget to render the correct counter value but it never updates.