Line data Source code
1 : import 'dart:async'; 2 : 3 : import 'package:flutter/widgets.dart'; 4 : 5 : import 'rx.dart'; 6 : 7 : /// A widget to be used with Observables (instances of Rx) 8 : /// 9 : /// ```dart 10 : /// import 'package:flutter/material.dart'; 11 : /// import 'package:flutter_meedu/meedu.dart'; 12 : /// import 'package:flutter_meedu/rx.dart'; 13 : /// 14 : /// class RxPage extends StatefulWidget { 15 : /// @override 16 : /// _RxPageState createState() => _RxPageState(); 17 : /// } 18 : /// 19 : /// class _RxPageState extends State<RxPage> { 20 : /// final _counter = Rx<int>(0); // create an observable 21 : /// 22 : /// @override 23 : /// void dispose() { 24 : /// _counter.close(); // You must call to close when you don't need the observable any more 25 : /// super.dispose(); 26 : /// } 27 : /// 28 : /// @override 29 : /// Widget build(BuildContext context) { 30 : /// return Scaffold( 31 : /// body: Center( 32 : /// child: RxBuilder( 33 : /// (_) => Text("${_counter.value}"), 34 : /// ), 35 : /// ), 36 : /// floatingActionButton: FloatingActionButton( 37 : /// onPressed: () { 38 : /// _counter.value++; 39 : /// }, 40 : /// ), 41 : /// ); 42 : /// } 43 : /// } 44 : /// ``` 45 : class RxBuilder extends StatefulWidget { 46 : // ignore: public_member_api_docs 47 2 : const RxBuilder(this.builder, {Key? key}) : super(key: key); 48 : 49 : /// the builder function 50 : final Widget Function(BuildContext context) builder; 51 : 52 1 : @override 53 : // ignore: library_private_types_in_public_api 54 1 : _RxBuilderState createState() => _RxBuilderState(); 55 : } 56 : 57 : class _RxBuilderState extends State<RxBuilder> { 58 1 : _RxBuilderState() { 59 2 : _observer = RxNotifier(); 60 : } 61 : 62 : RxNotifier? _observer; 63 : late StreamSubscription _subscription; 64 : bool _afterFirstLayout = false; 65 : 66 1 : @override 67 : void initState() { 68 1 : super.initState(); 69 4 : WidgetsBinding.instance.endOfFrame.then((_) { 70 1 : _afterFirstLayout = true; 71 : }); 72 : // listen the observable events 73 4 : _subscription = _observer!.listen(_rebuild); 74 : } 75 : 76 1 : @override 77 : void dispose() { 78 1 : _afterFirstLayout = false; 79 : // remove the subsciptions when the widget is destroyed 80 2 : _subscription.cancel(); 81 2 : if (_observer?.canUpdate ?? false) { 82 2 : _observer?.close(); 83 : } 84 : 85 1 : super.dispose(); 86 : } 87 : 88 1 : void _rebuild(_) { 89 2 : if (_afterFirstLayout && mounted) { 90 2 : setState(() {}); 91 : } 92 : } 93 : 94 1 : @override 95 : Widget build(BuildContext context) { 96 : final observer = RxNotifier.proxy; 97 : 98 1 : RxNotifier.proxy = _observer; 99 3 : final result = widget.builder(context); 100 2 : if (!_observer!.canUpdate) { 101 1 : throw FlutterError( 102 : ''' 103 : If you are seeing this error, you probably did not insert any observable variables into RxBuilder 104 : ''', 105 : ); 106 : } 107 : RxNotifier.proxy = observer; 108 : return result; 109 : } 110 : }