I Have Try to run my Flutter app using SplashScreen but when I back to drawer of App When it gives the error like : _SpinnerTextState#9863f(ticker active) was disposed with an active Ticker
I Used animated_splash_screen package for splash screen. When I back to my drawer that time screen just give the black color within microsecond and console gives the error
import 'package:animated_splash_screen/animated_splash_screen.dart';
import 'package:page_transition/page_transition.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'login/login.dart';
import 'pages/dashboard.dart';
import 'pages/drawer.dart';
var username;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
username = prefs.getString('username');
runApp(
MyApp(),
);
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
home: MasterScreen(),
);
}
}
class MasterScreen extends StatefulWidget {
#override
final AppBar appBar;
const MasterScreen({Key key, this.appBar}) : super(key: key);
#override
_MasterScreenState createState() => _MasterScreenState();
}
class _MasterScreenState extends State<MasterScreen> with SingleTickerProviderStateMixin {
AnimationController animationController;
Animation<double> animation;
var _visible = true;
#override
void initState() {
super.initState();
animationController = new AnimationController(
vsync: this,
duration: new Duration(seconds: 2),
);
animation =
new CurvedAnimation(parent: animationController, curve: Curves.easeOut);
animation.addListener(() => this.setState(() {}));
animationController.forward();
setState(() {
_visible = !_visible;
});
}
#override
dispose() {
animationController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
home:AnimatedSplashScreen(
curve: Curves.bounceIn,
splash: Image.asset(
'assets/logo.png',
height: 200,
width: 200,
),
nextScreen: username == null
? LoginScreen()
: AppDrawer(
child: DashBoard(
appBar: widget.appBar,
),
),
splashTransition: SplashTransition.scaleTransition,
pageTransitionType: PageTransitionType.leftToRightWithFade,
backgroundColor: Colors.blue,
animationDuration: Duration(
seconds: 2,
),
),
);
}
}
In above code AnimatedSplashScreen package is replace by simple SplashScreen package and we find the splash screen package here splash screen package here
SplashScreen(
backgroundColor: Colors.blue,
seconds: 5,
navigateAfterSeconds: LoginScreen(),
image: new Image.asset(
'assets/logo.png',
),
styleTextUnderTheLoader: new TextStyle(),
photoSize: 150.0,
loaderColor: Colors.white,
loadingText: Text(
'Welcome To QA Platform',
style: TextStyle(
color: Colors.white,
fontSize: 20,
),
),
),
Related
I am using Lottie Animation and want it to animate everytime I click on it , To this I am using GestureDetector However it only works the first time then for some reason it wont work again
Here is the code
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() async {
runApp(const App());
}
class App extends StatefulWidget {
const App({super.key});
#override
State<App> createState() {
return _AppState();
}
}
class _AppState extends State<App> with SingleTickerProviderStateMixin {
late final AnimationController my_location_controller;
#override
void initState() {
// TODO: implement initState
super.initState();
my_location_controller =
AnimationController(vsync: this, duration: const Duration(seconds: 5));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
color: Colors.lightBlue,
home: Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: SizedBox(
width: 300,
height: 300,
child: GestureDetector(
onTap: () {
my_location_controller.forward();
},
child: Lottie.asset(
'assets/my_location.json',
controller: my_location_controller,
animate: true,
repeat: true,
),
),
),
),
),
);
}
}
#Ante Bule thnx, will accept your answer and this seems to work too ..
child: GestureDetector(
onTap: () {
my_location_controller.reset();
my_location_controller.forward();
},
child: Lottie.asset(
'assets/my_location.json',
controller: my_location_controller,
),
Add a listener to reset your animation when it gets completed, like this:
#override
void initState() {
super.initState();
my_location_controller =
AnimationController(vsync: this, duration: const Duration(seconds: 5));
my_location_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
my_location_controller.reset();
}
});
}
I was working in Flutter to make an app and I only want the onboarding screen to be seen once by users. I have watched several videos showing how to do this, but the problem is my home screen will always be the Splash Screen. I am not sure how to use Shared Preferences to have the onboarding screen shown once but to still have the splash screen show every time. I could really use some assistance :).
My code for main.dart:
int? isViewed;
Future <void> main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
final showLogin = prefs.getBool('showLogin') ?? false;
Paint.enableDithering = true;
await Firebase.initializeApp();
// This is for our onboarding screen
isViewed = prefs.getInt('onboard');
runApp(MyApp(showLogin: showLogin));
}
class MyApp extends StatelessWidget {
final bool showLogin;
const MyApp({Key? key,
required this.showLogin}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Strength',
debugShowCheckedModeBanner: false,
theme: ThemeData(
appBarTheme: const AppBarTheme(color: Colors.white,
elevation: 0,
brightness: Brightness.light,
iconTheme: IconThemeData(color: Colors.black),
textTheme: TextTheme(headline6: TextStyle(color: Color(0xff888888), fontSize: 18),
)
),),
home: const SplashScreen(),
);
}
}
Chunks of code for my onboarding screen:
class OnboardingScreen extends StatefulWidget {
const OnboardingScreen({Key? key}) : super(key: key);
#override
_OnboardingScreenState createState() => _OnboardingScreenState();
}
class _OnboardingScreenState extends State<OnboardingScreen> {
final controller = PageController();
bool isLastPage = false;
#override
void dispose() {
controller.dispose();
super.dispose();
}
_storeOnboardingInfo() async {
int isViewed = 0;
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setInt('onBoard', isViewed);
}
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
.
.
.
TextButton(
style: TextButton.styleFrom(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
primary: Colors.white,
backgroundColor: const Color(0xff31708c),
minimumSize: const Size.fromHeight(60)
),
child: Text(
'Get Started',
style: GoogleFonts.montserrat(
fontSize: 24,
fontWeight: FontWeight.w600),
),
onPressed: () async {
final prefs = await SharedPreferences.getInstance();
prefs.setBool('showLogin', true);
await _storeOnboardingInfo();
Navigator.of(context).pushReplacement(
PageTransition(
type: PageTransitionType.fade,
duration: const Duration(milliseconds: 500),
child: LandingScreen()
)
);
}
)
Code for my Splash screen:
class SplashScreen extends StatefulWidget {
const SplashScreen ({Key? key}) : super(key: key);
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> with TickerProviderStateMixin{
late AnimationController _screenController;
#override
void initState() {
super.initState();
_screenController = AnimationController(vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child: Lottie.asset('assets/lottie/splashScreen.lottie.json',
fit: BoxFit.fill,
controller: _screenController,
onLoaded: (composition) {
_screenController
..duration = composition.duration
..forward().whenComplete(() =>
Navigator.of(context).pushReplacement(
PageTransition(
type: PageTransitionType.fade,
duration: const Duration(milliseconds: 1800),
child: const OnboardingScreen()
)
));
}
)
)
);
}
}
You can check the shared preference value in the Splash Screen and redirect the user to the OnBoardingScreen or LandingScreen.
import 'package:custom_form_field/src/form_screen.dart';
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SplashScreen extends StatefulWidget {
const SplashScreen({Key? key}) : super(key: key);
#override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with TickerProviderStateMixin {
late AnimationController _screenController;
#override
void initState() {
super.initState();
_screenController = AnimationController(vsync: this);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
height: double.infinity,
width: double.infinity,
child: Lottie.asset('assets/lottie/splashScreen.lottie.json',
fit: BoxFit.fill,
controller: _screenController, onLoaded: (composition) {
_screenController
..duration = composition.duration
..forward().whenComplete(() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
// check shared preference and show particular screen
});
})));
}
}
You can check the shared preference value at initState and do the logic after animation complete as well. Also you can check login state from shared preference here and show login page if needed.
Make a global variable :
Global.dart
library my_prj.globals;
bool newUser = true;
main.dart
globals.newUser == true ? LandingPage() : LoginPage()
signup.dart
Here i am passing the variable
globals.newUser = false;
along with Username or Password fields.
After then your value will be permanently set false until and unless you make a change on it.
I would like to ask you how to animate the size of an icon when you click on an image like on Instagram, Tiktok...
This is what I tried (and many other things) but without success.
GestureDetector(
onDoubleTap: (){
setState(() {
_showLikeAnimation = true;
_sizeFavoriteAnimation = 60.0; //old value is 20.0
});
},
child: Stack(
alignment: AlignmentDirectional.center,
children: [
_imagePost(),
AnimatedSize(curve: Curves.easeIn, duration: const Duration(seconds: 2), child: Icon(Icons.favorite, size: _sizeFavoriteAnimation))
],
)),
Would you have an idea?
One way you can achieve this is by using ScaleTransition and a CurvedAnimation. Below is a simple example.
When the user taps the icon, I change the look of the icon so it shows the latest state (active/not active) and I make it a little smaller. When this transition ends I make the icon big again. This is similar to how a button behaves in the real world when you press it. I hope this is what you had in mind.
class LikeButton extends StatefulWidget {
const LikeButton({Key? key}) : super(key: key);
#override
State<LikeButton> createState() => _LikeButtonState();
}
class _LikeButtonState extends State<LikeButton>
with SingleTickerProviderStateMixin {
late final AnimationController _controller = AnimationController(
duration: const Duration(milliseconds: 200), vsync: this, value: 1.0);
bool _isFavorite = false;
#override
void dispose() {
super.dispose();
_controller.dispose();
}
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
_isFavorite = !_isFavorite;
});
_controller
.reverse()
.then((value) => _controller.forward());
},
child: ScaleTransition(
scale: Tween(begin: 0.7, end: 1.0).animate(
CurvedAnimation(parent: _controller, curve: Curves.easeOut)),
child: _isFavorite
? const Icon(
Icons.favorite,
size: 30,
color: Colors.red,
)
: const Icon(
Icons.favorite_border,
size: 30,
),
),
);
}
}
You can use https://pub.dev/packages/lottie to animate,
try this;
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return const MaterialApp(title: 'Material App', home: LottieLearn());
}
}
class LottieLearn extends StatefulWidget {
const LottieLearn({Key? key}) : super(key: key);
#override
State<LottieLearn> createState() => _LottieLearnState();
}
class _LottieLearnState extends State<LottieLearn> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
final AnimationController darkmodeController =
AnimationController(vsync: this, duration: const Duration(seconds: 2));
final AnimationController favoriteController =
AnimationController(vsync: this, duration: const Duration(seconds: 1));
bool isLight = false;
bool isFavorite = false;
const String favoriteButton = "https://assets10.lottiefiles.com/packages/lf20_slDcnv.json";
const String darkMode = "https://assets10.lottiefiles.com/packages/lf20_tbyegho2.json";
return Scaffold(
appBar: AppBar(
actions: [
InkWell(
onTap: () async {
await darkmodeController.animateTo(isLight ? 0.5 : 1);
// controller.animateTo(0.5);
isLight = !isLight;
},
child: Lottie.network(darkMode, repeat: false, controller: darkmodeController)),
InkWell(
onTap: () async {
await favoriteController.animateTo(isFavorite ? 1 : 0);
isFavorite = !isFavorite;
},
child: Lottie.network(favoriteButton, repeat: false, controller: favoriteController)),
],
),
);
}
}
this must give you an idea, just "flutter pub add lottie" then copy paste code
So I am trying to find a way where I can press a button, change the background color then get back to the original color using tween.
Is there anyway I could possibly achieve this?
Here is an example of How you can change background with a tween.
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
// Remove the debug banner
debugShowCheckedModeBanner: false,
title: 'Tween',
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> with TickerProviderStateMixin {
late AnimationController _controller;
late Animation<Color?> _color;
#override
void initState() {
super.initState();
_controller = AnimationController(
duration: Duration(seconds: 5),
vsync: this,
);
_color =
ColorTween(begin: Colors.blue, end: Colors.amber).animate(_controller);
}
#override
void dispose() {
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
const SizedBox(height: 20),
AnimatedBuilder(
animation: _color,
builder: (BuildContext _, Widget? __) {
return Container(
width: 500,
height: 300,
decoration: BoxDecoration(
color: _color.value, shape: BoxShape.rectangle),
);
},
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () {
_controller.forward();
},
child: Text('Change background'),
),
SizedBox(height: 10),
ElevatedButton(
onPressed: () {
_controller.reverse();
},
child: Text('back to Orignal'),
),
],
),
);
}
}
I have this code which uses an AnimationController and Tween to rotate a container along Z-axis when Start/Stop Button is pressed. The problem is it forwards the animation only first time after that no matter how many times I press the button it does nothing and the container remains stationary .
curvesanimation.dart which has all the animation logic
import 'package:flutter/material.dart';
import 'dart:math' as math;
class CurvedAnimationExample extends StatefulWidget {
CurvedAnimationExample({Key key}) : super(key: key);
#override
CurvedAnimationExampleState createState() => CurvedAnimationExampleState();
}
class CurvedAnimationExampleState extends State<CurvedAnimationExample>
with SingleTickerProviderStateMixin {
Animation<double> _animation;
AnimationController _animationController;
#override
void initState() {
super.initState();
_animationController =
AnimationController(vsync: this, duration: Duration(seconds: 5))
..addListener(() {
setState(() {});
});
final Animation curve =
CurvedAnimation(parent: _animationController, curve: Curves.easeIn);
_animation = Tween<double>(begin: 0, end: math.pi * 2).animate(curve);
}
void startStopAnimation() {
print(_animationController.isAnimating.toString());
if (_animationController.isAnimating)
_animationController.stop();
else {
_animationController.forward();
}
}
#override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Transform(
alignment: Alignment.center,
transform: Matrix4.identity()..rotateZ(_animation.value),
child: Container(
color: Colors.pinkAccent,
width: 200,
height: 200,
),
),
RaisedButton(
child: const Text("Start/Stop Animation"),
elevation: 15,
color: Colors.blueGrey,
onPressed: () => startStopAnimation(),
)
],
));
}
#override
void dispose() {
_animationController.dispose();
print("Curved Animation Example : dispose is called");
super.dispose();
}
}
main.dart file
import 'package:flutter/material.dart';
import 'curvesanimations.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomeScaffold(
title: "Curved Animation Example",
),
);
}
}
class MyHomeScaffold extends StatelessWidget {
final String title;
MyHomeScaffold({this.title});
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(title),
),
body: CurvedAnimationExample(),
),
);
}
}
This is because your animation has already reached its endpoint. You can't keep going forward once the end point is reached. An easy fix is to check if the animation is at the endpoint already and reset it to the beginning if it is:
void startStopAnimation() {
print(_animationController.isAnimating.toString());
if (_animationController.isAnimating)
_animationController.stop();
else {
print("forward");
if(_animationController.isCompleted) {//Check if animation is at endpoint
_animationController.value = 0;
}
_animationController.forward();
}
}