How catch the opening and closing of the drawer in flutter? - flutter

How can I catch the opening and closing of the drawer in flutter? In principle, two objects must be are used for this purpose: DrawerController, which "holds" the drawer and the drawerCallback. drawerCallback should track the opening and closing of the drawer, but the code that is discussed at https://github.com/flutter/flutter/issues/21272 and https://github.com/flutter/flutter/issues/23630 does not works. Anyone can advise something?

Update 2021-12:
Scaffold(
drawer: DrawerWidget(),
onDrawerChanged: (isDrawerOpen) {
if(isDrawerOpen) {
//drawer is open
} else {
//drawer is close
}
},
body: bodyWidget(),
)
You can first refer to other people's replies on stackoverflow here
My solve:
get Drawer status on DrawerWidget
initState() : open drawer
dispose() : close drawer
Stream drawer status by DrawerService Provider
see full code
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:provider/provider.dart';
void main() {
runApp(
MultiProvider(
providers: [
Provider(create: (_) => DrawerService()),
],
child: MyApp(),
),
);
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
DrawerService _drawerService;
String drawerStatus = 'close';
#override
void initState() {
super.initState();
_drawerService = Provider.of(context, listen: false);
_listenDrawerService();
}
_listenDrawerService() {
_drawerService.status.listen((status) {
if(status) {
drawerStatus = 'open';
} else {
drawerStatus = 'close';
}
setState(() { });
});
}
#override
Widget build(BuildContext context) {
Color bgColor = Colors.yellow;
if(drawerStatus == 'open') {
bgColor = Colors.red;
}
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
drawer: DrawerWidget(),
body: Container(
decoration: BoxDecoration(color: bgColor),
height: 300,
child: Center(child: Text(drawerStatus),),
),
);
}
}
class DrawerWidget extends StatefulWidget {
#override
_DrawerWidgetState createState() => _DrawerWidgetState();
}
class _DrawerWidgetState extends State<DrawerWidget> {
DrawerService _drawerService;
#override
void initState() {
super.initState();
_drawerService = Provider.of(context, listen: false);
_drawerService.setIsOpenStatus(true);
}
#override
Widget build(BuildContext context) {
return Drawer(
child: Center(child: Text('drawer'),),
);
}
#override
void dispose() {
super.dispose();
_drawerService.setIsOpenStatus(false);
}
}
class DrawerService {
StreamController<bool> _statusController = StreamController.broadcast();
Stream<bool> get status => _statusController.stream;
setIsOpenStatus(bool openStatus) {
_statusController.add(openStatus);
}
}

Related

CupertinoPicker skip items in Desktop (Windows) in Flutter 3.7

Since updating to Flutter 3.7 i am not able to select cerain items in my CupertienoPicker.
To reproduce this issue run the following code in Windows Desktop:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _index = 0;
List<String> team = <String>["Olaf","Victor","Rita"] ;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CupertinoPicker(
itemExtent: 50,
onSelectedItemChanged: (selectedIndex) {
_index = selectedIndex;
},
children: List.generate(team.length, (index) {
return Text(team[index]);
}),
),
),
);
}
}
An issue has already filed in github.
First thing to check is your Mouse Settings. It is known that the issue might appear if you have set "Multiple lines at a time". To check this go to Settings -> Devices -> Mouse and set "Choose how many lines to scroll each time" to 1.
If this does not fix your issue read below.
The issue seems in deed a bug in the latest Flutter 3.7.
As a work around i had to add a listener to the CupertinoPicker's scrollerController and perform the jumps programatically as follows
var c = FixedExtentScrollController();
c.addListener(() {
if (previousIndex != c.selectedItem) {
isScrollDown = previousIndex<c.selectedItem;
isScrollUp = previousIndex>c.selectedItem;
var previousIndexTemp = previousIndex;
previousIndex = c.selectedItem;
if (isScrollUp) {
c.jumpToItem(previousIndexTemp - 1);
} else if (isScrollDown) {
c.jumpToItem(previousIndexTemp + 1);
}
}
});
...
CupertinoPicker(
scrollController: c,
...
Here is a modified version of the code above that applies the mentioned work around:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _index = 0;
int previousIndex = 0;
bool isScrollUp = false;
bool isScrollDown = true;
List<String> team = <String>["Olaf","Victor","Rita"] ;
FixedExtentScrollController c = FixedExtentScrollController();
#override
void initState() {
c.addListener(_manageScroll);
super.initState();
}
void _manageScroll () {
if (previousIndex != c.selectedItem) {
isScrollDown = previousIndex<c.selectedItem;
isScrollUp = previousIndex>c.selectedItem;
var previousIndexTemp = previousIndex;
previousIndex = c.selectedItem;
if (isScrollUp) {
c.jumpToItem(previousIndexTemp - 1);
} else if (isScrollDown) {
c.jumpToItem(previousIndexTemp + 1);
}
}
}
#override
void dispose() {
c.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: CupertinoPicker(
scrollController: c,
itemExtent: 50,
onSelectedItemChanged: (selectedIndex) {
_index = selectedIndex;
},
children: List.generate(team.length, (index) {
return Text(team[index]);
}),
),
),
);
}
}

flutter_osm_plugin: ^0.50.0-alpha.5 for web Cannot read properties of null (reading 'contentWindow')

import 'package:flutter/material.dart';
import 'package:flutter_osm_plugin/flutter_osm_plugin.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
routes: {
'/main': (context) => MyHomePage(title: 'Title'),
'/osm': (context) => Osm(),
},
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Osm(),
);
}
}
class Osm extends StatelessWidget {
const Osm({super.key});
#override
Widget build(BuildContext context) {
return Column(
children: [
TextButton(
onPressed: () {
Navigator.pushNamed(context, '/main');
},
child: const Text('Button'))
],
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late MapController controller;
#override
void dispose() {
controller.dispose();
super.dispose();
}
#override
void initState() {
controller = MapController(
initMapWithUserPosition: false,
initPosition: GeoPoint(latitude: 47.4358055, longitude: 8.4737324),
areaLimit: BoundingBox(
east: 10.4922941,
north: 47.8084648,
south: 45.817995,
west: 5.9559113,
),
);
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: OSMFlutter(
controller: controller,
trackMyPosition: false,
initZoom: 12,
minZoomLevel: 8,
maxZoomLevel: 14,
stepZoom: 1.0,
),
);
}
}
Add this line below 👇 in index.html in web folder
<script src="packages/flutter_osm_web/src/asset/map_init.js"></script>
When you first switch to a map widget, the map opens normally. If you return to the previous widget and go to the map again, an error occurs.
TypeError: Cannot read properties of null (reading 'contentWindow')
packages/flutter_osm_web/src/asset/map.js 182:65 setUpMap
packages/flutter_osm_web/src/controller/web_osm_controller.dart 141:35 initPositionMap
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 123:5 _async
packages/flutter_osm_web/src/controller/web_osm_controller.dart 137:31 initPositionMap
packages/flutter_osm_interface/src/map_controller/base_map_controller.dart 49:31
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/patch/async_patch.dart 84:54 runBody
If you restart, the card is loaded.I.e. the card opens only after restart.
Sometimes writes console: ChromeProxyService: Failed to evaluate expression 'androidOSMLifecycle': InternalError: Expression evaluation in async frames is not supported. No frame with index 16..
How to solve such a problem? The problem occurs on initPositionMap.

How to measure time of mounted widget in flutter?

I have a simple StopWatchController which i want to use to measure the time it takes to to mount SecondPage when clicking on the button next page in MyHomePage. I am not sure how i can achieve a succesfull return of the time between clicking and mounting. The return is always the start time when i debugPrint. How can i achieve a succesfull stopWatch.elapsed?
full code:
import 'package:flutter/material.dart';
class StopWatchController {
var stopWatch = Stopwatch();
stopWatchHandler(timer) {
if (timer == "start") {
stopWatch.start();
} else if (timer == "stop") {
stopWatch.stop();
debugPrint(stopWatch.elapsed.toString());
return stopWatch.elapsed.toString();
}
}
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
final String title;
const MyHomePage({
Key? key,
required this.title,
}) : super(key: key);
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: ElevatedButton(
child: Text("next page"),
onPressed: (){
Navigator.of(context)
.push(
MaterialPageRoute(
builder: (context) =>
const SecondPage()));
StopWatchController().stopWatchHandler("start");
}
)
),
);
}
}
class SecondPage extends StatefulWidget {
const SecondPage({
Key? key,
}) : super(key: key);
#override
State<SecondPage> createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
#override
initState(){
if (this.mounted == true) {
StopWatchController().stopWatchHandler("stop");
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
),
body: const Center(
child: Text("")
),
);
}
}
Edit
It debugPrint: 0:00:00.000000 when i press on next page
Try this in your stopWatchHandler(timer) function
stopWatchHandler(timer) {
if (timer == "start") {
stopWatch.start();
} else if (timer == "stop") {
stopWatch.stop();
debugPrint(stopWatch.elapsed.inMilliseconds.toString());
return "executed in ${stopwatch.elapsed.inMilliseconds}ms"; //<=== change-here
}
}

Flutter VLC Player implementation

Is there something I am missing setting up the VLC on flutter? Only empty. No player seen just a blank page here is my flutter code, just followed from their documentation. Here is the code. I might miss something. Is there any alternative way to use the VLC plugin? I am new to Flutter. Thank you
import 'package:flutter_vlc_player/flutter_vlc_player.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({key}) : super(key: key);
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
late VlcPlayerController _videoPlayerController;
#override
void initState() {
super.initState();
_videoPlayerController = VlcPlayerController.network(
'https://local.clift.mdu1.net/3ABN/index.m3u8',
hwAcc: HwAcc.FULL,
autoPlay: false,
options: VlcPlayerOptions(),
);
}
#override
void dispose() async {
super.dispose();
await _videoPlayerController.stopRendererScanning();
await _videoPlayerController.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: VlcPlayer(
controller: _videoPlayerController,
aspectRatio: 16 / 9,
placeholder: Center(child: CircularProgressIndicator()),
),
),
);
}
}```
try to add setstate in initState, or intime equal vlccontroller to VlcPlayerController.network

How can my Flutter FutureBuilder change text at multiple places in my layout?

I read carefully the Flutter tutorial; Fetching data from internet: https://flutter.io/cookbook/networking/fetch-data/
My concern is that I want to update multiple texts in my layout.
The implementation only shows a way to update one:
FutureBuilder<Post>(
future: fetchPost(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner
return CircularProgressIndicator();
},
);
This works fine and displays one view at a time.
In Android Studio/Java, I would have done something like:
myTextView1.setText(snapshot.data.data1)
myTextView2.setText(snapshot.data.data2)
myTextView3.setText(snapshot.data.data3)
.....
myTextView10.setText(snapshot.data.data3)
But here in Flutter, I am currently limited to one "Widget" at a time.
Of course, I could provide my whole layout in the return argument, but that would be crazy!
Any idea/suggestion?
An alternative strategy is to have a local variable in the state class and update it when the future arrives. Thus, you can reference that variable wherever you need.
Here is an example:
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Post _post = Post("Title 0", "Subtitle0 ", "description 0");
#override
void initState() {
super.initState();
_getPost();
}
void _getPost() async {
_post = await fetchPost();
setState(() {});
}
Future<Post> fetchPost() {
return Future.delayed(Duration(seconds: 4), () {
return Post("Title new", "Subtitle new", "description new");
});
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Center(
child: Column(
children: <Widget>[
new Text(_post.title),
new Text(_post.subtitle),
new Text(_post.description),
],
),
),
);
}
}
class Post {
final String title;
final String subtitle;
final String description;
Post(this.title, this.subtitle, this.description);
}
You can convert your request to Stream
import 'package:flutter/material.dart';
import 'package:random_pk/random_pk.dart';
import 'dart:async';
class TestWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() => _TestWidgetState();
}
class _TestWidgetState extends State<TestWidget> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(child: RandomContainer(
width: 200.0,
height: 200.0,
child: Center(child: _MyTextWidget(fetchPost().asStream())),
),),
);
}
Future<String> fetchPost() {
return Future.delayed(Duration(seconds: 4), () {
return "Title data";
});
}
}
class _MyTextWidget extends StatefulWidget {
_MyTextWidget(this.stream);
final Stream<String> stream;
#override
State<StatefulWidget> createState() => _MyTextWidgetState();
}
class _MyTextWidgetState extends State<_MyTextWidget> {
String text;
#override
void initState() {
widget.stream.listen((String data) {
setState(() {
text = data;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Text(text == null ? 'loading' : text);
}
}
In this example RandomContainer changes its color on every setState and it works as indicator, than changes are only in _MyTextWidget