I am trying to show a screen in flutter which should appear only for 10 seconds and then should disapper going back to previous screen. How this should be done in the correct manner in flutter. Is it possible to use timer.periodic in Flutter?
In the initstate of the screen that you wish to close add
Future.delayed(Duration(seconds: 10), (){
//Navigator.pushNamed("routeName");
Navigator.pop(context);
});
You can create new screen with Future.delayed inside initState
class NewPage extends StatefulWidget {
NewPage({Key? key}) : super(key: key);
#override
State<NewPage> createState() => _NewPageState();
}
class _NewPageState extends State<NewPage> {
#override
void initState() {
super.initState();
Future.delayed(Duration(seconds: 10)).then((value) {
Navigator.of(context).pop();
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
);
}
}
Related
I need to update a widget whenever the widget that's nested to it is updated.
Let's say widget A is nested in widget B, by the way we can have GlobalKey of widget A (if it can help to detect if the widget A is updated). Here, I need to update widget B whenever the widget A is updated, and in order to do it I need to check if the widget A is updated, if it is then I'll update widget B too.
You could do this for example:
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: B()));
}
class B extends StatefulWidget {
const B({super.key});
#override
State<B> createState() => BState();
}
class BState extends State<B> {
#override
Widget build(BuildContext context) {
print('B updates');
return Scaffold(
body: Column(
children: [A(updater: update)],
));
}
void update() {
setState(() {
});
}
}
class A extends StatefulWidget {
final Function? updater;
const A({Key? key, this.updater}) : super(key: key);
#override
State<A> createState() => _AState();
}
class _AState extends State<A> {
#override
void setState(VoidCallback fn) {
if (widget.updater != null) widget.updater!();
super.setState(fn);
}
#override
Widget build(BuildContext context) {
return TextButton(
onPressed: () {
setState(() {
print('clicked button');
});
},
child: const Text('click'));
}
}
Whenever the button is clicked it prints both "clicked button" as "B updates". So B rebuilds on each click. If you leave out the setState override in A you will see only the "clicked button" prints.
I use the package flutter_native_splash to display a splash screen. During this time, I want to instantiate a Future and, when it's done, I want to remove the splash screen and build a widget thanks to a FutureBuilder. The problem is that the device displays the splash screen AND the ErrorScreen for few milliseconds (I don't want it) before building the widget.
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
late Future<Metadata> futureMetadata;
#override
void initState() {
super.initState();
initialization();
}
void initialization() async {
futureMetadata = fetchMetadata();
FlutterNativeSplash.remove();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: FutureBuilder<Metadata>(
future: futureMetadata,
builder: (BuildContext context, AsyncSnapshot<Metadata> snapshot) {
if (snapshot.hasData) {
return NavBar(data: snapshot.data);
} else {
return const ErrorScreen();
}
}
)
);
}
}
FlutterNativeSplash.remove(); removes the splash screen.
because you want to remove the splashscreen after it's finished loading I think you want instead of
futureMetadata = fetchMetadata();
FlutterNativeSplash.remove();
do
futureMetadata = fetchMetadata();
await futureMetadata;
FlutterNativeSplash.remove();
I am using GetX. I need to listen changes in TextController. The follow code do not work:
class Controller extends GetxController{
final txtList = TextEditingController().obs;
#override
void onInit() {
debounce(txtList, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
}
Is does not print nothing when I am changing txtList value from UI. I suppose it's because it does not check text field inside txtList.
How to get it work?
You need to pass an RxInterface into debounce to do this via GetX. Just create an RxString and add a listener to the controller then pass the RxString into debounce.
class Controller extends GetxController {
final txtList = TextEditingController();
RxString controllerText = ''.obs;
#override
void onInit() {
txtList.addListener(() {
controllerText.value = txtList.text;
});
debounce(controllerText, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
}
Then on any page in the app you can pass in that controller into the textfield and it'll print the value after the user stops typing for 1 second.
class Home extends StatelessWidget {
final controller = Get.put(Controller());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: TextField(controller: controller.txtList), // this will print
),
);
}
}
And if you need that value for anything else it's also always accessible via controller.controllerText.value.
By TextEditingController.text, we can already get changing text input value so it does not need .obs.
To pass parameter for debounce, we should pass value itself : txtList.text. (see here: https://github.com/jonataslaw/getx/blob/master/documentation/en_US/state_management.md)
final txtList = TextEditingController(); // 1. here
#override
void onInit() {
debounce(txtList.text, (_) { // 2. here
print("debouce$_");
}, time: Duration(seconds: 1));
super.onInit();
}
This might work.
=================== added 11/21 ==================
Here's the example. I know the RxString variable seems a duplication for TextEditingController.text, but GetX's debounce function needs RxString type variable as a parameter. I tried to find more elegant way to do this, but I couldn't find anything. Please let me know if somebody knows a better way.
// in controller
late final TextEditingController textController;
final RxString userInput = "".obs;
#override
void onInit() {
super.onInit();
textController = TextEditingController();
userInput.value = textController.text;
textController.addListener(() {
userInput.value = textController.text;
}
);
debounce(userInput, (_) {
print("debouce$_");
}, time: Duration(seconds: 1));
}
check this snippet for example to listen to TextEditingController text change listener
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(),
darkTheme: ThemeData.dark(),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
final TextEditingController controller = TextEditingController();
#override
void initState() {
super.initState();
controller.addListener(_printLatestValue);
}
void _printLatestValue() {
print('Second text field: ${controller.text}');
}
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: TextField(
controller: controller,
),
);
}
}
My goal is to track routes being presented and dismissed for analytics purposes like described on this article: https://medium.com/flutter-community/how-to-track-screen-transitions-in-flutter-with-routeobserver-733984a90dea
I am pushing a CupertinoPageRoute and passing a Widget to it that implements the RouteAware Mixin.
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
return CupertinoApp(
...
navigatorObservers: [routeObserver],
}
Pushing like so:
Navigator.of(context).push(
CupertinoPageRoute(builder: (context) => MyWidget()),
);
The Widget
class MyWidget extends StatefulWidget {
MyWidget({Key key}) : super(key: key);
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> with RouteAware {
#override
void didChangeDependencies() {
super.didChangeDependencies();
routeObserver.subscribe(this, ModalRoute.of(context));
}
#override
void dispose() {
routeObserver.unsubscribe(this);
super.dispose();
}
#override
void didPop() {
print('never called');
}
#override
void didPopNext() {
print('never called');
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
children: [
CupertinoNavigationBar(
middle: Text('42'),
),
],
),
);
}
}
The didPop() method is never called when popping a CupertinoPageRoute with the back button unless I push with rootNavigator = true which is not what I want.
How can I fix this?
EDIT: This behavior only happens when pushing routes from a CupertinoTabView, as it creates a new nested navigator.
Github Issue
If I understand correctly, the final solution shown in the Medium article does not extend every StatefulWidget with RouteAware. Instead, it extents its own implementation of a RouteObserver to get notified about every route change.
Using this approach, you should be able to insert your custom RouteObserver into both you main App as well as your CupertinoTabView to achieve what you need.
I am facing an issue in which dispose method is not called after changing screen in flutter .First of all here is the source code.
class Game extends StatefulWidget {
Game({Key key, this.title}) : super(key: key);
final String title;
#override
_GameState createState() => new _GameState();
}
class _GameState extends State<Game> with SingleTickerProviderStateMixin {
final CrosswordController myController = CrosswordController();
var chewieController = null;
var videoPlayerController = null;
Widget makeVideoStreaming(){
videoPlayerController = VideoPlayerController.network("https://somelink.com");
chewieController = ChewieController(//paramtere here
);
}
#override
void initState() {
super.initState();
this.makeVideoStreaming();
_controller = AnimationController(vsync: this, duration: Duration(minutes: gameTime));
}
#override
void dispose(){
print('DISPOSE CALLED- GAME---');
videoPlayerController.dispose();
chewieController.dispose();
_controller.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: _onBackPressed,
child: Scaffold(
key: _scaffoldKey,
drawer: NavigationDrawer(),
resizeToAvoidBottomPadding: false,
body://body here
),
);
}
}
In NavigationDrawer() i changes to some different route something like this.
onTap: () {
Navigator.pop(context); Navigator.pushNamed(context, '/edit_profile');
},
Above is just a part of code which is called after clicking on one of the item from drawer list item.
In GameState dispose method is not called why ?
Dispose method called when you remove screen from stack mean's that when you use navigator.pop() Or pushReplacement;
it's a known bug: https://github.com/flutter/flutter/issues/40940
even if you copy examples from official docs, it will not get called: https://flutter.dev/docs/cookbook/networking/web-sockets#complete-example
I've started a thread of flutter-dev to find out if something else should be used instead: https://groups.google.com/g/flutter-dev/c/-0QZFGO0p-g/m/bictyZWCCAAJ