How to play rive animation onTap? - flutter

I was happy bcs there was easy solution for flare package, but unfortunately now I have .riv format, so there is only rive package for me.
All examples I saw where playing animation instantly after screen loaded, but I need it to be started with function (button, onpressed etc).
class Animation extends StatefulWidget {
#override
_AnimationState createState() => _AnimationState();
}
class _AnimationState extends State<Animation> {
RiveAnimationController controller;
#override
void initState() {
super.initState();
controller = SimpleAnimation('Animation 1');
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: RiveAnimation.asset(
'match.riv',
controllers: [controller],
),
),
);
}
}
thank you in advance

From rive's official documentation, pass one more parameter to SimpleAnimation
class PlayPauseAnimation extends StatefulWidget {
const PlayPauseAnimation({Key? key}) : super(key: key);
#override
_PlayPauseAnimationState createState() => _PlayPauseAnimationState();
}
class _PlayPauseAnimationState extends State<PlayPauseAnimation> {
// Controller for playback
late RiveAnimationController _controller;
// Toggles between play and pause animation states
void _togglePlay() =>
setState(() => _controller.isActive = !_controller.isActive);
/// Tracks if the animation is playing by whether controller is running
bool get isPlaying => _controller.isActive;
#override
void initState() {
super.initState();
_controller = SimpleAnimation('Animation 1', autoplay: false);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RiveAnimation.network(
'match.riv',
controllers: [_controller],
// Update the play state when the widget's initialized
onInit: (_) => setState(() {}),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _togglePlay,
tooltip: isPlaying ? 'Pause' : 'Play',
child: Icon(
isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}

Related

Why won't my Dart Video App code compile?

I'm working on a Flutterflow project and when I attempt to compile my widget inside of the custom widget section it returns multiple errors. Here is the code directly from pub.dev and I am adding the dependencies in the right section but I am continually getting the same errors.
import 'package:video_player/video_player.dart';
void main() => runApp(const VideoApp());
/// Stateful widget to fetch and then display video content.
class VideoApp extends StatefulWidget {
const VideoApp({Key? key}) : super(key: key);
#override
_VideoAppState createState() => _VideoAppState();
}
class _VideoAppState extends State<VideoApp> {
late VideoPlayerController _controller;
#override
void initState() {
super.initState();
_controller = VideoPlayerController.network(
'https://flutter.github.io/assets-for-api-docs/assets/videos/bee.mp4')
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Video Demo',
home: Scaffold(
body: Center(
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}

Is it possible to create a video player in stateless widget in flutter?

I was trying to create a videoplayer in a stateless widget in flutter. I could not do it.... this is the code I used ...Is it possible to create a video player in a stateless widget?
class VideoWidget extends StatelessWidget {
VideoWidget({Key? key}) : super(key: key);
final videoController =
VideoPlayerController.network('https://youtu.be/_EoLNs5m-7Y?t=4')
..initialize();
#override
Widget build(BuildContext context) {
return SizedBox(
width: MediaQuery.of(context).size.width,
//height: 500,
child: Column(
children: [
//VideoPlayer(videoController!),
ValueListenableBuilder(
valueListenable: videoPlayerNotifier,
builder: (BuildContext cxt, play, widget_) {
return videoController.value.isInitialized
? AspectRatio(
aspectRatio: videoController.value.aspectRatio,
child: VideoPlayer(videoController))
: Container();
}),
const Text(
'movieName',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const Text('Description'),
FloatingActionButton(onPressed: () {
videoPlayerNotifier.value = true;
})
],
),
);
}
}
VideoPlayer from the video_player pub package is quite stateful, due especially to VideoPlayerController. However, you can wrap it in a StatefulWidget to be used within a StatelessWidget. E.g. use this wrapper within a stateless widget:
class VideoPlayerWrapper extends StatefulWidget {
final String videoUri;
const VideoPlayerWrapper({Key? key, required this.videoUri}) : super(key: key);
#override
_VideoPlayerWrapperState createState() => _VideoPlayerWrapperState(videoUri);
}
class _VideoPlayerWrapperState extends State<VideoPlayerWrapper> {
late VideoPlayerController _controller;
final String videoUri;
_VideoPlayerWrapperState(this.videoUri);
#override
void initState() {
super.initState();
_controller = VideoPlayerController.network(videoUri)
..initialize().then((_) {
// Ensure the first frame is shown after the video is initialized, even before the play button has been pressed.
setState(() {});
});
_controller.play();
}
#override
Widget build(BuildContext context) {
return Center(
child: _controller.value.isInitialized
? AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
);
}
#override
void dispose() {
super.dispose();
_controller.dispose();
}
}

Is there a way to navigate pages white keeping the same background in flutter

I'm trying to build a flutter app where I'm mainly keeping the background the same and the pages that the user uses just stack up on top of the background. Is there any way to navigate from one screen to another whilst keeping the background the same? My main layout for this app is a Stack widget where i keep my background widget there and the widget on top is the one we want to navigate out off.
Any help will be appreciated!
maybe you are looking for something like pageview
https://api.flutter.dev/flutter/widgets/PageView-class.html
simple setstate Example, with a counter
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("simple setstate Example"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_counter == 0 ? new Page1() : new Container(),
_counter == 1 ? new Page2() : new Container(),
_counter == 2 ? new Page3() : new Container(),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class Page1 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.red,
height: 200.0,
);
}
}
class Page2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
height: 200.0,
);
}
}
class Page3 extends StatefulWidget {
#override
_Page3State createState() => _Page3State();
}
class _Page3State extends State<Page3> {
double opacityLevel = 0.0;
#override
void initState() {
// TODO: implement initState
super.initState();
Timer(Duration(milliseconds: 500), () {
setState(() => opacityLevel = opacityLevel == 1 ? 0.0 : 1.0);
});
}
#override
Widget build(BuildContext context) {
return AnimatedOpacity(
opacity: opacityLevel,
duration: Duration(seconds: 3),
child: Container(
color: Colors.green,
height: 200.0,
),
);
}
}

SlideAnimation Not Starting Again After Calling SetState()

I made a simple class for animating a widget into the screen:
class CustomSlideAnimation extends StatefulWidget {
static const String FROM_LEFT = 'FROM_LEFT';
static const String FROM_RIGHT = 'FROM_RIGHT';
final String from;
final Widget child;
const CustomSlideAnimation(
{Key key, this.from = FROM_LEFT, #required this.child})
: super(key: key);
#override
_CustomSlideAnimationState createState() => _CustomSlideAnimationState();
}
class _CustomSlideAnimationState extends State<CustomSlideAnimation>
with SingleTickerProviderStateMixin {
Animation<Offset> _offsetAnimation;
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(milliseconds: 300));
_offsetAnimation = widget.from == CustomSlideAnimation.FROM_LEFT
? Tween<Offset>(
begin: Offset(-1.0, 0.0),
end: Offset.zero,
).animate(CurvedAnimation(
curve: Curves.linear,
parent: _animationController,
))
: Tween<Offset>(
begin: Offset(1.0, 0.0),
end: Offset.zero,
).animate(CurvedAnimation(
curve: Curves.linear,
parent: _animationController,
));
_animationController.forward();
}
#override
void dispose() {
super.dispose();
_animationController.dispose();
}
#override
Widget build(BuildContext context) {
return SlideTransition(
position: _offsetAnimation,
child: widget.child,
);
}
}
And a simple app to demonstrate the problem:
void main() => runApp(Test());
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
bool widget1 = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: widget1
? CustomSlideAnimation(
child: InkWell(
child: Text('widget1'),
onTap: () {
setState(() {
widget1 = false;
});
},
),
from: CustomSlideAnimation.FROM_LEFT,
)
: CustomSlideAnimation(
child: InkWell(
child: Text('widget2'),
onTap: () {
setState(() {
widget1 = true;
});
},
),
from: CustomSlideAnimation.FROM_LEFT,
),
),
),
);
}
}
When I start the app for first time the Text widget as expected slides in to the screen,
but then I tap it and thus calling setState() the second Text widget just appears suddenly into the screen and no slide transition happens.
I printed the times when build get called in all the classes and I see that setState() is triggering builds in Test and CustomSlideTransition classes but not triggering initState() in the CustomSlideTransition.
EDIT for more clarification: even putting controller.forward() inside the build() method didn't work.
So what am I missing?
You just need to add a UniqueKey() to every CustomSlideAnimation() to tell flutter to treat them like different widgets.
void main() => runApp(Test());
class Test extends StatefulWidget {
#override
_TestState createState() => _TestState();
}
class _TestState extends State<Test> {
bool widget1 = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: widget1
? CustomSlideAnimation(
key: UniqueKey(),
child: InkWell(
child: Text('widget1'),
onTap: () {
setState(() {
widget1 = false;
});
},
),
from: CustomSlideAnimation.FROM_LEFT,
)
: CustomSlideAnimation(
key: UniqueKey(),
child: InkWell(
child: Text('widget2'),
onTap: () {
setState(() {
widget1 = true;
});
},
),
from: CustomSlideAnimation.FROM_LEFT,
),
),
),
);
}
}
Also, keep controller.forward() inside initState()
I figured it out, the reason is in the keys and widget trees as explained in this video.
When the setState was called without CustomSlideTransition having a unique key, then the framework did not recreate the State object of this class again and it instead used the State object of the previous widget which had the AnimationStatus as completed
But now with keys each time the framework creates a new State object and calls initState() where the controller is reset and the animation starts normally.
I also found a workaround but I don't know if it is as efficient as the "keys" solution:
Without adding a key to the CustomSlideTransition widget,I can, in the build() method of this widget, do these two commands:
_animationController.reset();
_animationController.forward();
and remove the call to _animationController.forward(); in initState().

Rebuilding a Widget in a column

So I have 2 widgets in a column. 1 is a listview of containers and another is a Column of TabBar and TabBarView. I wrote this code which helps me store the current index is the TabView selected
TabController _tabController;
void initState() {
super.initState();
_tabController = new TabController(vsync: this, length: 4);
_tabController.addListener(() {
globals.tabIndex = _tabController.index;
});
}
As per the image I want to change the color of the tile as the active listview changes (Active container is blue). The containers have an onTap functions which changes their color as they are pressed. Is there anyway I can rebuild the top containers when the listview Index changes?
You can simply call the setState function to rebuild the widget;
import 'dart:ui';
import 'package:flutter/material.dart';
import 'dart:async';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Example(),
),
);
}
}
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> with SingleTickerProviderStateMixin {
TabController _tabController;
void initState() {
super.initState();
_tabController = TabController(vsync: this, length: 4);
_tabController.addListener(() {
setState(() {});
});
}
#override
void dispose() {
_tabController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Row(
children: <Widget>[
_Item(
isActive: _tabController.index == 0,
onTap: () => _tabController.animateTo(0),
),
_Item(
isActive: _tabController.index == 1,
onTap: () => _tabController.animateTo(1),
),
_Item(
isActive: _tabController.index == 2,
onTap: () => _tabController.animateTo(2),
),
_Item(
isActive: _tabController.index == 3,
onTap: () => _tabController.animateTo(3),
),
],
),
TabBar(
controller: _tabController,
tabs: <Widget>[
_TabItem(
'one',
),
_TabItem('two'),
_TabItem('three'),
_TabItem('four'),
],
)
],
);
}
}
class _TabItem extends StatelessWidget {
final String title;
const _TabItem(this.title, {Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Text(
title,
style: TextStyle(color: Colors.black),
);
}
}
class _Item extends StatelessWidget {
final bool isActive;
final Function onTap;
const _Item({Key key, this.isActive, this.onTap}) : super(key: key);
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onTap,
child: Container(
height: 80,
width: 50,
color: isActive ? Colors.blue : Colors.grey,
child: Text('hey'),
),
);
}
}
Hey there created a simple example to show how you would achieve this. Uses all the components you mentioned, tabBar, TabBarView, ListViewBuilder to create the list.
And onTap of the element use the tabController to animate to the Tab. And this subsequently trigger the addListener callaback which updates the currentSelected Index.
https://dartpad.dev/5f5475b790fe9a75b26c1f686adab96e