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.
Related
When the app opens up, I want the logo and app name to pop up, and pause it for a few seconds before redirecting to the next directory. Can anyone please help me because I'm new to flutter and have been stuck for awhile >_<
import 'package:flutter/material.dart';
class wlcPage extends StatelessWidget {
const wlcPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Container(
height: double.infinity,
width: double.infinity,
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage('images/appBckgrd.jpg'),
fit: BoxFit.cover
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const CircleAvatar(
radius: 80,
backgroundImage: AssetImage("images/logo.png"),
),
Text('signhouse',
style: TextStyle(
fontFamily: 'OpenSans',
fontSize: 30,
fontWeight: FontWeight.normal,
letterSpacing: 1,
color: Colors.teal[700],
),
),
],
),
),
),
);
}
}
You can use the Future.delayed function to your advantage and make it wait for a couple of seconds and then use the Navigator.push() to show your other page.
Please try below plugin to display logo and different style of text when app opens up. The duration property sets delay between the splash screen and target screen. Provider Duration in millisecond.
splash_screen_view: ^3.0.0
You can also try below code (without use of plugin) example with Timer to pause the screen for sometime
import 'dart:async';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Splash Screen',
theme: ThemeData(
primarySwatch: Colors.green,
),
home: MyHomePage(),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
super.initState();
Timer(Duration(seconds: 3),
()=>Navigator.pushReplacement(context,
MaterialPageRoute(builder:
(context) =>
SecondScreen()
)
)
);
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white,
child:FlutterLogo(size:MediaQuery.of(context).size.height)
);
}
}
class SecondScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title:Text("Data")),
body: Center(
child:Text("Home page",textScaleFactor: 2,)
),
);
}
}
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;
});
},
),
],
);
}
}
Hero animation is the best for navigating between screen, but I need same animation between widgets. Like one card moving another place for example: Product Card moves to shoppingcart and something else. Thanks for answers!
Try this one, add_to_cart_animation:
import 'package:add_to_cart_animation/add_to_cart_animation.dart';
import 'package:add_to_cart_animation/add_to_cart_icon.dart';
import 'package:flutter/material.dart';
import 'list_item.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: 'Add To Cart Animation',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Add To Cart Animation'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// We can detech the location of the card by this GlobalKey<CartIconKey>
GlobalKey<CartIconKey> gkCart = GlobalKey<CartIconKey>();
late Function(GlobalKey) runAddToCardAnimation;
var _cartQuantityItems = 0;
#override
Widget build(BuildContext context) {
return AddToCartAnimation(
// To send the library the location of the Cart icon
gkCart: gkCart,
rotation: true,
dragToCardCurve: Curves.easeIn,
dragToCardDuration: const Duration(milliseconds: 1000),
previewCurve: Curves.linearToEaseOut,
previewDuration: const Duration(milliseconds: 500),
previewHeight: 30,
previewWidth: 30,
opacity: 0.85,
initiaJump: false,
receiveCreateAddToCardAnimationMethod: (addToCardAnimationMethod) {
// You can run the animation by addToCardAnimationMethod, just pass trough the the global key of the image as parameter
this.runAddToCardAnimation = addToCardAnimationMethod;
},
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
centerTitle: false,
actions: [
// Improvement/Suggestion 4.4 -> Adding 'clear-cart-button'
IconButton(
icon: Icon(Icons.cleaning_services),
onPressed: () {
_cartQuantityItems = 0;
gkCart.currentState!.runClearCartAnimation();
},
),
SizedBox(width: 16),
AddToCartIcon(
key: gkCart,
icon: Icon(Icons.shopping_cart),
colorBadge: Colors.red,
),
SizedBox(
width: 16,
)
],
),
body: ListView(
children: [
AppListItem(onClick: listClick, index: 1),
AppListItem(onClick: listClick, index: 2),
AppListItem(onClick: listClick, index: 3),
AppListItem(onClick: listClick, index: 4),
AppListItem(onClick: listClick, index: 5),
AppListItem(onClick: listClick, index: 6),
AppListItem(onClick: listClick, index: 7),
],
),
),
);
}
// Improvement/Suggestion 4.4 -> Running AddTOCartAnimation BEFORE runCArtAnimation
void listClick(GlobalKey gkImageContainer) async {
await runAddToCardAnimation(gkImageContainer);
await gkCart.currentState!.runCartAnimation((++_cartQuantityItems).toString());
}
}
OR
[not null safety]
this is a sample of add to cart, add_cart_parabola:
import 'dart:ui';
import 'package:add_cart_parabola/add_cart_parabola.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
GlobalKey floatKey = GlobalKey();
GlobalKey rootKey = GlobalKey();
Offset floatOffset ;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_){
RenderBox renderBox = floatKey.currentContext.findRenderObject();
floatOffset = renderBox.localToGlobal(Offset.zero);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
key: rootKey,
width: double.infinity,
height: double.infinity,
color: Colors.grey,
child: ListView(
children: List.generate(40, (index){
return generateItem(index);
}).toList(),
),
),
floatingActionButton: FloatingActionButton(
backgroundColor: Colors.yellow,
key: floatKey,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget generateItem(int index){
Text text = Text("item $index",style: TextStyle(fontSize:
25),);
Offset temp;
return GestureDetector(
onPanDown: (details){
temp = new Offset(details.globalPosition.dx, details.globalPosition
.dy);
},
onTap: (){
Function callback ;
setState(() {
OverlayEntry entry = OverlayEntry(
builder: (ctx){
return ParabolaAnimateWidget(rootKey,temp,floatOffset,
Icon(Icons.cancel,color: Colors.greenAccent,),callback,);
}
);
callback = (status){
if(status == AnimationStatus.completed){
entry?.remove();
}
};
Overlay.of(rootKey.currentContext).insert(entry);
});
},
child: Container(
color: Colors.orange,
child: text,
),
);
}
}
For animating widget in the same screen you can use AnimatedPositioned widget see the below code
import 'dart:math';
import 'package:flutter/material.dart';
class AnimatedPositionedDemo extends StatefulWidget {
const AnimatedPositionedDemo({Key? key}) : super(key: key);
static String routeName = 'animated_positioned';
#override
_AnimatedPositionedDemoState createState() => _AnimatedPositionedDemoState();
}
class _AnimatedPositionedDemoState extends State<AnimatedPositionedDemo> {
late double topPosition;
late double leftPosition;
double generateTopPosition(double top) => Random().nextDouble() * top;
double generateLeftPosition(double left) => Random().nextDouble() * left;
#override
void initState() {
super.initState();
topPosition = generateTopPosition(30);
leftPosition = generateLeftPosition(30);
}
void changePosition(double top, double left) {
setState(() {
topPosition = generateTopPosition(top);
leftPosition = generateLeftPosition(left);
});
}
#override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
final appBar = AppBar(title: const Text('AnimatedPositioned'));
final topPadding = MediaQuery.of(context).padding.top;
// AnimatedPositioned animates changes to a widget's position within a Stack
return Scaffold(
appBar: appBar,
body: SizedBox(
height: size.height,
width: size.width,
child: Stack(
children: [
AnimatedPositioned(
top: topPosition,
left: leftPosition,
duration: const Duration(seconds: 1),
child: InkWell(
onTap: () => changePosition(
size.height -
(appBar.preferredSize.height + topPadding + 50),
size.width - 150),
child: Container(
alignment: Alignment.center,
width: 150,
height: 50,
child: Text(
'Click Me',
style: TextStyle(
color:
Theme.of(context).buttonTheme.colorScheme!.onPrimary,
),
),
color: Theme.of(context).primaryColor,
),
),
),
],
),
),
);
}
}
I hope it works for you
For Animated widgets, flutter team has provided a video on youtube here
And you can read all about them on their website here
Using the scrollListener and ScrollController, how can I get the scroll distance from start to the end of the scrolling each time the user scroll?
ScrollController has a property called offset which will give you the current offset.
A working example follows
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',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
ScrollController controller = ScrollController();
double initialPosition = 0.0;
double endPosition = 0.0;
double distance = 0.0;
#override
void initState() {
super.initState();
controller = ScrollController();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: NotificationListener(
onNotification: (notif) {
if(notif is ScrollStartNotification) {
initialPosition = controller.offset;
} else if(notif is ScrollEndNotification) {
endPosition = controller.offset;
distance = endPosition - initialPosition;
print(distance);
}
return true;
},
child: ListView(
controller: controller,
children: <Widget>[
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
Container(
height: 100.0,
color: Colors.red,
),
],
),),
);
}
}
UPDATE: Added code which helps in detecting start and end scroll.
Animations created with Flare Flutter (from 2dimensions.com) cannot switch between different animations of the same Flare Actor. If a black version is first, the white version will not display; if the white version is first, the black will display.
I am not sure if I am doing something wrong or if it is a bug. It can switch between colors, just not animations.
import 'package:flutter/material.dart';
import 'package:flare_flutter/flare_actor.dart';
const List<String> animations = ['White', 'Black'];
const List<Color> colors = [Colors.blue, Colors.black];
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Animation Tester',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Animation Tester'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int index = 0;
void switchAnimation() {
setState(() {
index = index < (animations.length - 1) ? index + 1 : 0;
});
}
#override
Widget build(BuildContext context) {
print(index);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView(
children: <Widget>[
GestureDetector(
onTap: switchAnimation,
child: Icon(
Icons.add,
size: 100.0,
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/color_wheel_loading.flr',
color: colors[index],
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/color_wheel_loading.flr',
animation: animations[index],
)),
Center(child: Text('$index'))
],
)),
);
}
}
I have tested your code with my own file, it works perfect. May be your animation names are not right, can you check.
Or you can test this file "https://www.2dimensions.com/a/whitewolfnegizzz/files/flare/pj" and using the code below.
import 'package:flutter/material.dart';
import 'package:flare_flutter/flare_actor.dart';
const List<String> animations = ['Build and Fade Out', 'Build'];
const List<Color> colors = [Colors.blue, Colors.black];
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Animation Tester',
debugShowCheckedModeBanner: false,
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Animation Tester'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int index = 0;
void switchAnimation() {
setState(() {
index = index < (animations.length - 1) ? index + 1 : 0;
});
}
#override
Widget build(BuildContext context) {
print(index);
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ListView(
children: <Widget>[
GestureDetector(
onTap: switchAnimation,
child: Icon(
Icons.add,
size: 100.0,
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/color_wheel_loading.flr',
color: colors[index],
)),
Container(
width: 200.0,
height: 200.0,
child: FlareActor(
'assets/Pj.flr',
animation: animations[index],
)),
Center(child: Text('$index'))
],
)),
);
}
}
From what i observed, Flare animation names are case sensitive. If the animation names in the flare project are in lowercase, the animation property of your flare actor should also be in lowercase.
Add flr in assets.
initialize it in Pubsepec.yaml file
then add dependency of flare animation in pubsepec.yaml file
after this,
just use this code in your main file
Container(
height: MediaQuery.of(context).size.height *0.8,
child: FlareActor(
'assets/oncemore.flr',
animation: 'Celebrate Duplicate', // Check this, when you are downloading flr file from Flare 2D dimension website
fit: BoxFit.contain,
),
),
After this , Your Flare animation will work perfectly.