How to automatically hide the status bar after scrolling it down? - android

I want to automatically hide the status bar after 3 seconds of scrolling it down.
currently, I'm doing this.
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
Timer.periodic(const Duration(seconds: 3), (timer) {
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen();
);
}
}
I want the timer to begin as soon as the user scrolls the the status bar.
Is there any better way to do that?

You may face existing issue on SystemChrome.
When setting System UI Overlays to bottom or top only, the status bar/bottom will show persistently after clicking.
Flutter problem full-screen on android #23913
SystemChrome.setEnabledSystemUIOverlays isn't sticky on android when only disable top #28426
I provide a workaround solution that detect status bar appear and react to it by using WidgetsBindingObserver
class _MyAppState extends State<MyApp> with WidgetsBindingObserver {
var count = 0;
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
...
#override void didChangeMetrics() {
count++;
Future.delayed(const Duration(seconds: 3), () {
if(count == 1) {
SystemChrome.restoreSystemUIOverlays();
}
count --;
});
}
...
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}

Related

Update data every time a screen is shown on device in Flutter

I have a flutter app with redux state management.
In my app, I want to refetch some data from server when some other data in other screen changed. But in my case, I navigate from screen1 to screen2, and some data chaned in screen 2. I use a boolean flag needUpdate saved to redux and set to true after changes on screen 2.
But when I navigate back to screen1, I need to refetch data if the flag is true. But it did not work and data didnt refetch.
Here is some code:
class FirstScreen extends StatefulWidget {
const FirstScreen({Key? key}) : super(key: key);
#override
State<StatefulWidget> createState() => _FirstScreenState();
}
class _FirstScreenState extends State<FirstScreen> {
#override
void initState() {
super.initState();
}
#override
void didChangeDependencies() async {
final store = StoreProvider.of<AppState>(context);
var needUpdate = store.state.commonState?.needUpdate.value ?? false;
if (needUpdate) {
await store.dispatch(prepareData(context));
}
}
#override
Widget build(BuildContext context) {}
}
class SecondScreen extends StatefulWidget {
const SecondScreen({Key? key}) : super(key: key);
#override
State<SecondScreen> createState() => _SecondScreenState();
}
class _SecondScreenState extends State<SecondScreen> {
#override
void initState() {
super.initState();
}
void onPress() async {
await store.dispatch(ChangeNeedUpdatePortfolio(true));
Navigator.pop(context);
}
#override
Widget build(BuildContext context) {}
}
and Here is my action:
ThunkAction<AppState> updatePortfolioData(BuildContext context) {
return (Store<AppState> store) async {
bool needUpdate = store.state.commonState?.needUpdate.value ?? false;
if (needUpdate) {
...
await store.dispatch(ChangeNeedUpdatePortfolio(false));
...
return;
}
};
}

How to detect a phone shake in Flutter?

i tried to get run the ShakeDetector in my Flutter app. I got a sample app here. Can somebody help me to fix the problem?
This codesample below is from the shake.dart github example. I dont get it why it is not working.
import 'package:flutter/material.dart';
import 'package:shake/shake.dart';
void main() {
runApp(DemoPage());
}
class DemoPage extends StatefulWidget {
#override
_DemoPageState createState() => _DemoPageState();
}
var phoneShakes;
class _DemoPageState extends State<DemoPage> {
#override
void initState() {
super.initState();
ShakeDetector detector = ShakeDetector.autoStart(onPhoneShake: () {
print('shaking');
});
// To close: detector.stopListening();
// ShakeDetector.waitForStart() waits for user to call detector.startListening();
phoneShakes = detector.mShakeCount;
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: AppBar(
title: Text(phoneShakes.toString()),
),
);
}
}
It's because there was no call to setState. Try this code:
class _DemoPageState extends State<DemoPage> {
late ShakeDetector _detector;
#override
void initState() {
super.initState();
_detector = ShakeDetector.autoStart(onPhoneShake: () {
setState(() {}); // Call setState every time phone shakes.
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Text('Count: ${_detector.mShakeCount}'),
),
);
}
}

how can progress-bar listen value changes using flutter provider and update another widget?

**this is my provider **
MultiProvider(
child: MyApp(),
providers: [
ChangeNotifierProvider(create: (BuildContext context)=> Downloads(),),)]
***this class implements notifylistner when i print out _progress it all works properly
but the ui wiget does not rebuid to give out the outputs ***
class Downloads extends ChangeNotifier {
int _progress= 0;
int get progress => _progress;
void setProgress(int p) {
_progress = p;
notifyListeners();
}
}
i have removed progress-bar widget to make it simple instead show output value
class FileDownload extends StatelessWidget {
const FileDownload({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(body: progessUi());
}
}
class progessUi extends StatelessWidget {
const progessUi({Key key}) : super(key: key);
#override
Widget build(BuildContext context) {
final model = Provider.of<Downloads>(context);
return Container(child: Text(model.progress.toString()));
}
}
*this just a snippet where the calls to the Download function are made *
if (message['event'] == EV_PROGRESS) {
Downloads().setProgress(message['progress']);
}
if (message['event'] == EV_DONE) {
Downloads().setProgress(100);
}

Flutter Shake Detector doesn't detect phone's shake

I'm using Shake Flutter package in order to detect shakes on my application, but it doesn't seem to work either on my physical device (Samsung Galaxy A71) or on my Android Emulator.
Here is how I initialise the ShakeDetector:
class _HomePageState extends State<HomePage> {
bool _hasShaked;
ShakeDetector _shakeDetector;
#override
void initState() {
super.initState();
_hasShaked = false;
_shakeDetector = ShakeDetector.autoStart(
onPhoneShake: () {
print('shake')
setState(() {
_hasShaked = true;
_shakeDetector.stopListening();
});
},
);
}
#override
Widget build(BuildContext context) {
// ...
}
}
I tried to use ShakeDetector#waitForStart() instead but it doesn't work either:
class _HomePageState extends State<HomePage> {
bool _hasShaked;
ShakeDetector _shakeDetector;
#override
void initState() {
super.initState();
_hasShaked = false;
_shakeDetector = ShakeDetector.waitForStart(
onPhoneShake: () {
print('shake')
setState(() {
_hasShaked = true;
_shakeDetector.stopListening();
});
},
);
_shakeDetector.startListening();
}
#override
Widget build(BuildContext context) {
// ...
}
}
Here is my dependencies in my pubspec.yaml:
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.3
shake: ^0.1.0
Thanks for the help.

How to get Android Activity Lifecycle Events in Flutter Plugin? [duplicate]

Are there any Activity lifecycle methods in Flutter apps?
Like:
onCreate()
onResume()
onDestroy()
Or:
viewDidload()
viewWillAppear()
How to handle application lifecycle when making an app with Flutter?
There is a method called when the system put the app in the background or return the app to foreground named didChangeAppLifecycleState.
Example with widgets:
class _AppLifecycleReactorState extends State<AppLifecycleReactor> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
AppLifecycleState _notification;
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
setState(() { _notification = state; });
}
#override
Widget build(BuildContext context) {
return new Text('Last notification: $_notification');
}
}
Also there are CONSTANTS to know the states that an application can be in, eg:
inactive
paused
resumed
suspending
The usage of these constants would be the value of the constant e.g:
const AppLifecycleState(state)
Run the following code, press the home button and then reopen the app to see it working. There are 4 AppLifecycleState:
resumed: The application is visible and responding to user input.
inactive: The application is in an inactive state and is not receiving user input.
paused: The application is not currently visible to the user, not responding to user input, and running in the background.
detached: The application is still hosted on a flutter engine but is detached from any host views.
Null safe code:
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> with WidgetsBindingObserver {
#override
void initState() {
super.initState();
WidgetsBinding.instance!.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance!.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
print('Current state = $state');
}
#override
Widget build(BuildContext context) => Scaffold();
}
To be notified when app goes to foreground or route popped you can inherit LifecycleState class and override onResume() and onPause() methods. LifecycleState class:
/// Inherit this State to be notified of lifecycle events, including popping and pushing routes.
///
/// Use `pushNamed()` or `push()` method to track lifecycle events when navigating to another route.
abstract class LifecycleState <T extends StatefulWidget> extends State<T>
with WidgetsBindingObserver {
ResumeResult resumeResult = new ResumeResult();
bool _isPaused = false;
AppLifecycleState lastAppState = AppLifecycleState.resumed;
void onResume() {}
void onPause() {}
/// Use instead of Navigator.push(), it fires onResume() after route popped
Future<T> push<T extends Object>(BuildContext context, Route<T> route, [String source]) {
_isPaused = true;
onPause();
return Navigator.of(context).push(route).then((value) {
_isPaused = false;
resumeResult.data = value;
resumeResult.source = source;
onResume();
return value;
});
}
/// Use instead of Navigator.pushNamed(), it fires onResume() after route popped
Future<T> pushNamed<T extends Object>(BuildContext context, String routeName, {Object arguments}) {
_isPaused = true;
onPause();
return Navigator.of(context).pushNamed<T>(routeName, arguments: arguments).then((value) {
_isPaused = false;
resumeResult.data = value;
resumeResult.source = routeName;
onResume();
return value;
});
}
#override
void initState() {
super.initState();
WidgetsBinding.instance.addObserver(this);
}
#override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
#override
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.paused) {
if (!_isPaused) {
onPause();
}
} else if (state == AppLifecycleState.resumed &&
lastAppState == AppLifecycleState.paused) {
if (!_isPaused) {
onResume();
}
}
lastAppState = state;
}
}
class ResumeResult {
dynamic data;
String source;
}
Also make sure to start push new routes using push() or pushNamed() method.

Categories

Resources