I'm trying to pinch zoom an image that I have created in a separate widget, this widget is being called inside a dialog. Image gets loaded but not being pinched in and out.
here is my widget code:
class ImageWidget extends StatefulWidget {
const ImageWidget({Key? key}) : super(key: key);
#override
State<ImageWidget> createState() => _ImageWidgetState();
}
class _ImageWidgetState extends State<ImageWidget>
with SingleTickerProviderStateMixin {
final double minScale = 1;
final double maxScale = 4;
late TransformationController _transformationController;
late AnimationController _animationController;
Animation<Matrix4>? animation;
#override
void initState() {
// TODO: implement initState
super.initState();
_transformationController = TransformationController();
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300))
..addListener(() {
_transformationController.value = animation!.value;
});
}
#override
void dispose() {
_transformationController.dispose();
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return InteractiveViewer(
transformationController: _transformationController,
clipBehavior: Clip.none,
minScale: minScale,
maxScale: maxScale,
onInteractionEnd: (details) {
resetAnimation();
},
panEnabled: false,
scaleEnabled: false,
child: AspectRatio(
aspectRatio: 2,
child: Image.asset(
'assets/capture.jpg',
),
));
}
void resetAnimation() {
animation = Matrix4Tween(
begin: _transformationController.value, end: Matrix4.identity())
.animate(
CurvedAnimation(parent: _animationController, curve: Curves.ease));
_animationController.forward(from: 0);
}
}
and here is how I called it inside the dialog:
onTap: () async {
await showDialog(
context: context, builder: (_) => const ImageWidget());
},
I'd be glad if anyone can help me out with it, thanks in advance!
Related
I have the following splash screen and I want to insert an animated video instead of the logo image.
I tried to follow this tutorial https://www.youtube.com/watch?v=ySaVFCpK4M8&t=102s
and it made me change the whole code but I ended up stuck with a black screen.
so i need to modify the code below to view the video instead of the image.
any help will be appreciated thank you.
import 'package:cirilla/constants/assets.dart';
import 'package:cirilla/constants/constants.dart';
import 'package:flutter/material.dart';
import 'package:ui/painter/zoom_painter.dart';
import 'widgets/zoom_animation.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key, this.color, this.loading}) : super(key: key);
final Color? color;
final bool? loading;
#override
State<SplashScreen> createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with SingleTickerProviderStateMixin {
Size size = Size.zero;
late AnimationController _controller;
late ZoomAnimation _animation;
AnimationStatus _status = AnimationStatus.forward;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 2500),
vsync: this,
)
..addStatusListener((AnimationStatus status) {
setState(() {
_status = status;
});
})
..addListener(() {
setState(() {});
});
_animation = ZoomAnimation(_controller);
}
#override
void didChangeDependencies() {
setState(() {
size = MediaQuery.of(context).size;
});
super.didChangeDependencies();
}
#override
void didUpdateWidget(covariant SplashScreen oldWidget) {
super.didUpdateWidget(oldWidget);
if (!widget.loading! && _controller.status != AnimationStatus.forward) {
_controller.forward();
}
}
#override
Widget build(BuildContext context) {
if (_status == AnimationStatus.completed) return Container();
return Stack(children: [
SizedBox(
width: double.infinity,
height: double.infinity,
child: CustomPaint(
painter: ZoomPainter(color: widget.color!, zoomSize: _animation.zoomSize.value * size.width),
),
),
Padding(
padding: const EdgeInsets.only(bottom: itemPaddingExtraLarge),
child: Align(
alignment: Alignment.center,
child: Opacity(
opacity: _animation.textOpacity.value,
child: Image.asset(Assets.logo, width: 200, height: 200, fit: BoxFit.fitWidth),
),
),
)
]);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}
I have this code that makes the icon rotate clockwise. I want to make it rotate anticlockwise. how can I do that?
animationController =
AnimationController(vsync: this, duration: Duration(seconds: 3))
..repeat(reverse: true);
RotationTransition(
turns: animationController,
child: Icon(Icons.settings_sharp),
alignment: Alignment.center,
)
Concerning RotationTransition widget rotation direction is manipulated by turns property.
When widget rotates clockwise controllers value goes from 0.0 to 1.0.
To rotate in opposite direction you need value to go from 1.0. to 0.0.
To achieve that, you can set up Tween:
final Tween<double> turnsTween = Tween<double>(
begin: 1,
end: 0,
);
And animate this tween in turns property with any AnimationController you need:
child: RotationTransition(
turns: turnsTween.animate(_controller),
...
Sample result and code to reproduce:
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 const MaterialApp(
title: _title,
home: 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.
/// AnimationControllers can be created with `vsync: this` because of TickerProviderStateMixin.
class _MyStatefulWidgetState extends State<MyStatefulWidget>
with TickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
duration: const Duration(seconds: 4),
vsync: this,
)..repeat();
final Tween<double> turnsTween = Tween<double>(
begin: 1,
end: 0,
);
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RotationTransition(
turns: turnsTween.animate(_controller),
child: const Padding(
padding: EdgeInsets.all(8.0),
child: FlutterLogo(size: 150.0),
),
),
),
);
}
}
You can add in an AnimationBuilder and Animation object and set the end Tween property to negative.
Also, It looked like you were attempting to have the widget reverse rotation upon completion in a cycle? If so, I added in the code for that too if it helps :)
For example:
#override
void initState() {
_controller =
AnimationController(vsync: this, duration: Duration(seconds: 3))
//To have the widget change rotation direction upon completion
..addStatusListener((status) {
if(status == AnimationStatus.completed)
_controller.reverse();
if(status == AnimationStatus.dismissed){
_controller.forward();
}
});
_animTurn = Tween<double>(begin: 0.0, end: -1.0).animate(_controller);
_controller.forward();
super.initState();
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: _controller,
builder: (context, child) {
return
RotationTransition(
turns: _animTurn,
child: Icon(Icons.settings_sharp,size: 100,),
alignment: Alignment.center,
);
});
}
}
I'm trying to animate a container in a FutureBuilder widget which makes a request to a node js api on localhost. There seems to have no issues with the API, but I've noticed that the Container renders normally when I don't call controller.repeat(). i'm guessing that controller.repeat() doesn't work well asynchronously, but I haven't found any alternatives.
This is the code I've got so far:
class _HomeState extends State<Home> with SingleTickerProviderStateMixin {
AnimationController controller;
Animation<double> animation;
void initState() {
super.initState();
controller = AnimationController(
duration: const Duration(milliseconds: 3000), vsync: this);
animation = Tween<double>(begin: 10, end: 300).animate(controller);
animation.addListener(() {
setState(() {});
});
}
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final url = Uri.parse("http://localhost:8080");
return FutureBuilder(
future: http.get(url),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final themeList =
Map<String, dynamic>.from(jsonDecode(snapshot.data.body));
final keys = List.from(themeList.keys);
controller.repeat(); // Container shows when I comment this line out
return Center(
child: Container(
color: Colors.red,
width: animation.value,
height: animation.value,
),
);
} else {
return Center(child: CircularProgressIndicator());
}
});
}
}
Please separate your animated widget. In your code, every setState(...) call will re-request the http.get(...).
Do something like this...
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: const Scaffold(
body: Center(
child: Home(),
),
),
);
}
}
class Home extends StatelessWidget {
const Home();
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: Future<void>.delayed(const Duration(seconds: 2), () {}),
builder: (context, snapshot) =>
snapshot.connectionState == ConnectionState.done
? const Center(child: AnimatedContainer())
: const Center(child: CircularProgressIndicator()),
);
}
}
class AnimatedContainer extends StatefulWidget {
const AnimatedContainer();
#override
_AnimatedContainer createState() => _AnimatedContainer();
}
class _AnimatedContainer extends State<AnimatedContainer>
with SingleTickerProviderStateMixin {
AnimationController _controller;
Animation<double> _animation;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 3000),
vsync: this,
);
_animation = Tween<double>(begin: 10, end: 300).animate(_controller);
_animation.addListener(() {
setState(() {});
});
// _controller.repeat();
_controller.forward();
}
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
width: _animation.value,
height: _animation.value,
);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
}
I have a text widget I want to rotate for 360 degrees only on Y axis.
Here is the code I currently have, it only rotates up to a certain point.
import 'package:flutter/material.dart';
class Loader extends StatefulWidget {
#override
_LoaderState createState() => _LoaderState();
}
class _LoaderState extends State<Loader> with SingleTickerProviderStateMixin {
Animation _rotate;
AnimationController _controller;
#override
void initState() {
super.initState();
_controller = new AnimationController(
vsync: this,
duration: new Duration(seconds: 1),
);
_rotate = Tween(begin: 0.0, end: 3.14 * 2).animate(_controller);
_controller.forward();
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return Container(
child: AnimatedBuilder(
animation: _controller,
child: Text("Flutter"),
builder: (BuildContext context, Widget _widget) {
return Transform(
transform: Matrix4.rotationY(_controller.value),
child: _widget,
);
},
),
);
}
}
Do you guys have any idea how to fix this?
Thanks!
add this
_rotate = Tween(begin: 0.0, end: 3.14 * 2).animate(_controller)
..addListener(() {
setState(() {});
});
I am trying to generate a list in flutter which delays every item after some delay.
I was tried using FutureBuilder and AnimatedList but i failed to get it.
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Example(),
);
}
}
class Example extends StatefulWidget {
#override
_ExampleState createState() => new _ExampleState();
}
class _ExampleState extends State<Example> with TickerProviderStateMixin{
AnimationController listViewController;
final Animation listView;
Duration duration = new Duration(seconds: 3);
Timer _timer;
#override
void initState() {
listViewController = new AnimationController(
duration: new Duration(seconds: 2),
vsync: this
);
super.initState();
}
FlutterLogoStyle _logoStyle = FlutterLogoStyle.markOnly;
item() {
_timer = new Timer(const Duration(seconds: 1), () {
return Text("cdscs");
});
}
#override
void dispose() {
listViewController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("hello"),
),
// ListView Builder
body: AnimatedList(
initialItemCount: 10,
itemBuilder: (BuildContext context,
int index,
Animation<double> animation){
return item();
},
)
);
}
}
You could use the AnimationController and an Animation for every child like this example:
class Example extends StatefulWidget {
#override
_ExampleState createState() => new _ExampleState();
}
class _ExampleState extends State<Example> with TickerProviderStateMixin {
AnimationController _animationController;
double animationDuration = 0.0;
int totalItems = 10;
#override
void initState() {
super.initState();
final int totalDuration = 4000;
_animationController = AnimationController(
vsync: this, duration: new Duration(milliseconds: totalDuration));
animationDuration = totalDuration/(100*(totalDuration/totalItems));
_animationController.forward();
}
FlutterLogoStyle _logoStyle = FlutterLogoStyle.markOnly;
#override
void dispose() {
_animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("hello"),
),
// ListView Builder
body: ListView.builder(
itemCount: totalItems,
itemBuilder: (BuildContext context, int index) {
return new Item(index: index, animationController: _animationController, duration: animationDuration);
},
));
}
}
class Item extends StatefulWidget {
final int index;
final AnimationController animationController;
final double duration;
Item({this.index, this.animationController, this.duration});
#override
_ItemState createState() => _ItemState();
}
class _ItemState extends State<Item> {
Animation _animation;
double start;
double end;
#override
void initState() {
super.initState();
start = (widget.duration * widget.index ).toDouble();
end = start + widget.duration;
print("START $start , end $end");
_animation = Tween<double>(
begin: 0.0,
end: 1.0,
).animate(
CurvedAnimation(
parent: widget.animationController,
curve: Interval(
start,
end,
curve: Curves.easeIn,
),
),
)..addListener((){
setState(() {
});
});
}
#override
Widget build(BuildContext context) {
return Opacity(
opacity: _animation.value,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text("New Sample Item ${widget.index}"),
),
);
}
}
You can change the animation, in this case I was using opacity to simulate fade animation.
Maybe you can Check this response: https://stackoverflow.com/a/59121771/9481448
for (var i = 0; i < fetchedList.length; i++) {
future = future.then((_) {
return Future.delayed(Duration(milliseconds: 100), () {
// add/remove item
});
});