I have a DefaultTabController that is getting longer and longer in code. As a beginner, I see I might miss some class / oop knowledge here.
I want to move its children to new files. I already have Widget TabContent1 and Widget TabContent2 in the same class, but how can I move these widgets to new files? The problem is that they both load values of TextEditingControllers on the TabController level. Moving the two Widgets breaks the reference to these TextEditingControllers. How can I refer to those from the newly created classes?
Update: In addition. As suggested by Ivo, I can put all references in the constructor of my new class. But I have a lot of global controllers and variables in the top level class. Also need to bind to the events happening in my new class and have to emit those back or so. It feels more efficient to keep my logic, but only move some of it to sub-classes or so. I feel like the solution should be more in oop/class logic, implementing or extending them
Related
When creating a Flutter application,
we use a Navigator to move back and forth between screens.
In my application, I have some class instances that
I want to share with all child widgets in the hierarchy.
An example is a Data Base driver class (stateful)
which holds all functionality of reading/writing to the actual database.
Currently - the 'main' function is initializing it,
then the resulting object is passed through all
constructors of the participating widgets.
How do I make it behave like the Navigator
so it would be available in the global scope
without importing it or passing it through a chain of constructors?
I would gladly accept any other approaches,
and still, if you can also address the exact question - I would be grateful :)
I opened the code of Navigator, Stateless and Stateful widgets,
I tried to google for the source of that Navigator instance
but came up with nothing helpful.
Have you tried using InheritedWidget?
From the docs:
Base class for widgets that efficiently propagate information down the tree.
Create DataBaseDriver class as inherited Widget class, access it in its child class using context as DataBaseDriver.of(context)
In Android, every Fragment can partecipate in populating the options menu (aka "appBar actions", in flutter terms) of the activity, using the Fragment.onCreateOptionsMenu callback.
I would like a similar mechanism also in flutter, i.e. that some widgets are able to add buttons ("actions") to the AppBar.
Threads had already been opened on this topic, but none reports a fully functional example and contains solutions to the precise technical problem I encountered.
To do this, I had thought of using the following 'typical' structure:
a StatefulWidget -to which I have given name ScaffoldHandler (ScaffoldHandlerWidget/ScaffoldHandlerState)- which wraps the entire Scaffold, and which uses InheritedWidget so that widgets further down the widgets tree can get a reference to it in an optimal way (using the classic of() method which executes dependOnInheritedWidgetOfExactType()).
ScaffoldHandlerState keeps in a field the actions set by the various children, and supplies them to the app-bar.
a widget that creates the AppBar. In the build() method it gets the actions to be displayed calling ScaffoldHandlerState.of().
mixin ScaffoldChild on State, which applied to a widget gives it the ability to add actions to ScaffoldHandlerState.
Internally, ScaffoldChild executes ScaffoldHandlerState.of() in didChangeDependencies() (to add actions) and in deactivate() (to remove them).
I originally used initState() and dispose() but this did not handle the case where a ScaffoldChild changes position while not being permanently removed from the widgets tree.
The problem I encountered is that ScaffoldAppBar.build is executed before ScaffoldChild.didChangeDependencies, so when the app-bar is created, ScaffoldChild still has to put its actions in ScaffoldHandlerState.
The curious thing is that this problem is due to the simple linear order in which ScaffoldAppBar and ScaffoldChild are inserted in the page: if instead of a top app-bar I want to create a bottom app-bar, the problem is not there because ScaffoldChild.didChangeDependencies would run before ScaffoldAppBar.build.
As a workaround to overcome the problem, I have inserted in ScaffoldChild.didChangeDependencies a call to scaffoldHandler.setState scheduled by WidgetsBinding.instance.addPostFrameCallback(): thus, after the actions have been inserted in ScaffoldHandler, the app-bar is updated with the new actions.
However, this solution seems like a hack to me.
In stackoverflow I see a lot of problems solved with addPostFrameCallback + setState, and sometimes that solution avoids really understanding where it goes wrong; I am interested in understanding if there are better solutions because my purpose, as well as practical, was to better understand the lifecycle of widgets.
Is there a better solution?
This is my code:
DartPad or Gist
(I tried to shorten it as much as possible, but sorry if it's not really short)
I'm building my first Flutter app, in which I need to refresh a list of data, and every component has some modifiers.
This is the basic architecture.
A big list of data (about 5000 rows) is periodically refreshed from an API inside a RefresherWidget (which is a StatefulWidget that holds the list), and then passed along to the children.
Every RowWidget has a Switch (and Dialogs too) that modifies the data it represents.
Currently, the methods to modify the list are in the RefresherWidget, so I'm passing them as callback functions inside every children until reaching the onChanged callback of the Switch.
But I don't think it's a very clean solution, and I don't know how to implement a better one: I've tried thinking about passing these methods inside an InheritedWidget that stays between RefresherWidget and ListViewWidget, and referencing them using the of function, but I don't know about the perfomance hit I would get if the InheritedWidget gets rebuild.
Also, Streams and BLoCs seem very complicated for what I need to do.
How do you guys usually approach a problem like this?
This is definitely a situation for InheritedWidget or BuildContext in general.
I've tried [...] InheritedWidget [...] but I don't know about the perfomance hit I would get if the InheritedWidget gets rebuild.
You don't have to fear anything. InheritedWidget is built for this exact purpose.
Obtaining the InheritedWidget is very performant (O(1)). And only widgets that depends on the value gets rebuilt – which is optimal too.
I just want to know if this is the proper way to go about splitting up widgets in GWT that get too large, or if I am missing the concept of widgets/proper GWT usage all together.
I started out with a single class (widget), PCBuilder. As PCBuilder became too large, I decided to branch off and make two classes SuggestionPanel, and BuildControlPanel, both of which just split off PCBuilder's code into separate classes that still have access to the methods in PCBuilder:
This way, in my PCBuilder class, I can do something like this to add the SuggestionPanel and the BuildControlPanel to the tabs (TabLayoutPanel) that are specified in the UiBinder of PCBuilder while allowing for SuggestionPanel and BuildControlPanel to have their own separate UiBinder specifications:
My question is: Is this proper? Part of me thinks "no" just because it's not a nice way of doing it. On the other hand it works just fine, and my web application is somewhat broken up into manageable "sections" which is what I wanted.
Thanks for any insight.
It's fine apart from the fact that you have circular dependencies between classes.
Why do SuggestionPanel and BuildControlPanel need to call PCBuilder? Is there any business logic in it? RPC maybe? Separate that into another class.
First, you might want to take a look at GIN - this handles dependency injection. This is good for testability.
Second, if your app goes beyond one "page", then take a look at GWT MVP.
You should not consider your PCBuilder as a widget. Quoting gwt -
You construct user interfaces in GWT applications using widgets that are contained within panels. Widgets allow you to interact with the user. Panels control the placement of user interface elements on the page.
Coming back to your question, my take is to create widgets only if I can reuse the same element more than once. The rest of my layout logic goes into the view. Layout shouldn't be a part of the definition of the widget as much as possible.To conclude, push styling in css, push layout in the views; widgetize only if re-usable (and core) or if adding additional functionality to existing widgets.
first post don't hurt me :)
I am using a BorderLayout with the usual North, West, Center, South Panels. On the West ContentPanel, I've got a Tree. If an event (OnClick)occurs I want a particular dialog box displayed on the Center ContentPanel.
What is the best way for me to do this? Currently I'm using a function called returnPanel() that returns the center ContentPanel. In the event handler I call this function (MainWindow.returnPanel().add(myDialog)).
The way you are doing it is intuitive and works, but will start causing hell when the application grows, because different parts of the application are strongly coupled. The solutions to this problems are the MVC design pattern and the observer design pattern.
Ideally, using the MVC pattern, you don't want any widget to 'know' of any other widget. There is only class that knows all the widgets, which is the Controller. Anytime one widget needs to message/signal another widget, it tells it to the Controller class, which relays the message in the appropriate way to the appropriate widget. In this way, the two widgets are decpoupled and one can change without breaking the other. You may want to use an enum to enumerate all possible actions to which the controller has to responsd.
If your widget has to call only the Controller when an event occurs, you may simply call an aptly named (static) method on it and be done with it. However, as soon as multiple other classes needs to be informed of an event, you are better of using the Observer pattern, which allows you to signal multiple other classes, without changing your class. It simply calls notifyPObservers() in the eventHandler and that's it. How many listeners there are, and what type they are, is irrelevant. This way, you also decouple a class from it's listeners. Even if only the Controller listens, it may be advisable to use the pattern, as it clearly seperated the 'call back' code from the other code in the classes.
BTW, this has nothing to do with GWT or even Java in particular.