Closed cliftonlabrum closed 1 week ago
Hi @cliftonlabrum!
Either you configure the areas via controller
or via initialAreas
(which will generate an internal controller). But you can't use both at the same time, okay?
Thanks for your quick reply! π I wondered about that and tried it. If I delete initialAreas
so I have this:
MultiSplitView splitView = MultiSplitView(
controller: UI.to.splitViewController,
);
...I still get the same exception. π
If I do the opposite and only use initialAreas
, it works without crashing. But I need a controller since I dynamically set my Area
flex
values depending on which page of my app is shown.
It used to work for me in version 2.4.0
. I had it in a StatelessWidget
and controlled the state via a ChangeNotifier
. It seems the internal and external state may be in conflict. π€
Actually, the line of code it's blaming for the issue is slightly different if I use only a controller
:
The relevant error-causing widget was:
LayoutBuilder LayoutBuilder:
file:///.../.pub-cache/hosted/pub.dev/multi_split_view-3.1.0/lib/src/multi_split_view.dart:175:12
I believe there is some state problem with this watch_it
package.
I made this code using the simple static package.
import 'package:flutter/material.dart';
import 'package:multi_split_view/multi_split_view.dart';
import 'package:watch_it/watch_it.dart';
void main() {
// UI.to.setup();
UI.to2.setup();
runApp(const MultiSplitViewExampleApp());
}
class UI with ChangeNotifier {
// static UI get to => di<UI>();
static UI to2 = UI();
final MultiSplitViewController controller = MultiSplitViewController();
setup() {
controller.areas = [
Area(builder: (context, area) => Draft.blue()),
Area(builder: (context, area) => Draft.yellow()),
Area(builder: (context, area) => Draft.green())
];
}
}
class MultiSplitViewExampleApp extends StatelessWidget {
const MultiSplitViewExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MultiSplitViewExample(),
);
}
}
class MultiSplitViewExample extends StatefulWidget {
const MultiSplitViewExample({Key? key}) : super(key: key);
@override
MultiSplitViewExampleState createState() => MultiSplitViewExampleState();
}
class MultiSplitViewExampleState extends State<MultiSplitViewExample> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Multi Split View Example')),
body: MultiSplitViewTheme(
data: MultiSplitViewThemeData(
dividerPainter: DividerPainters.grooved2()),
child: MultiSplitView(controller: UI.to2.controller)));
}
}
Using the watch_it
package, I get the error:
Rejecting promise with error: Bad state: GetIt: Object/factory with type UI is not registered inside GetIt.
(Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;
Did you forget to register it?)
Try registering it first like this:
void main() {
di.registerSingleton<UI>(UI());
UI.to2.setup();
runApp(const MultiSplitViewExampleApp());
}
:thinking: Now it's working here... I'm using multi_split_view 3.2.0
import 'package:flutter/material.dart';
import 'package:multi_split_view/multi_split_view.dart';
import 'package:watch_it/watch_it.dart';
void main() {
di.registerSingleton<UI>(UI());
UI.to.setup();
//UI.to2.setup();
runApp(const MultiSplitViewExampleApp());
}
class UI with ChangeNotifier {
static UI get to => di<UI>();
//static UI to2 = UI();
final MultiSplitViewController controller = MultiSplitViewController();
setup() {
controller.areas = [
Area(builder: (context, area) => Draft.blue()),
Area(builder: (context, area) => Draft.yellow()),
Area(builder: (context, area) => Draft.green())
];
}
}
class MultiSplitViewExampleApp extends StatelessWidget {
const MultiSplitViewExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MultiSplitViewExample(),
);
}
}
class MultiSplitViewExample extends StatefulWidget {
const MultiSplitViewExample({Key? key}) : super(key: key);
@override
MultiSplitViewExampleState createState() => MultiSplitViewExampleState();
}
class MultiSplitViewExampleState extends State<MultiSplitViewExample> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Multi Split View Example')),
body: MultiSplitViewTheme(
data: MultiSplitViewThemeData(
dividerPainter: DividerPainters.grooved2()),
child: MultiSplitView(controller: UI.to.controller)));
}
}
This code doesn't work for you?
flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[β] Flutter (Channel stable, 3.19.6, on Ubuntu 22.04.4 LTS 6.5.0-35-generic, locale en_US.UTF-8)
[β] Android toolchain - develop for Android devices (Android SDK version 32.0.0)
[β] Chrome - develop for the web
[β] Linux toolchain - develop for Linux desktop
[β] Android Studio (version 2023.2)
[β] IntelliJ IDEA Community Edition (version 2023.3)
[β] IntelliJ IDEA Community Edition (version 2022.3)
[β] VS Code (version 1.73.1)
[β] Connected device (2 available)
[β] Network resources
β’ No issues found!
Your sample works for me. If I reduce my app to a really simple sample, it still crashes.
It's crashing on this line:
Area area = controllerHelper.areas.last;
...because areas
is temporarily empty so the last
causes an array crash.
This fixes it for me:
if (controllerHelper.areas.isNotEmpty) {
Area area = controllerHelper.areas.last;
}
The only thing I can think of is that it's some kind of race condition where the areas aren't ready yet.
Apparently the method is just not prepared for a list of empty areas. I added the button to remove all areas and an error occurred. It's the same right?
import 'package:flutter/material.dart';
import 'package:multi_split_view/multi_split_view.dart';
import 'package:watch_it/watch_it.dart';
void main() {
di.registerSingleton<UI>(UI());
UI.to.setup();
//UI.to2.setup();
runApp(const MultiSplitViewExampleApp());
}
class UI with ChangeNotifier {
static UI get to => di<UI>();
//static UI to2 = UI();
final MultiSplitViewController controller = MultiSplitViewController();
setup() {
controller.areas = [
Area(builder: (context, area) => Draft.blue()),
Area(builder: (context, area) => Draft.yellow()),
Area(builder: (context, area) => Draft.green())
];
}
}
class MultiSplitViewExampleApp extends StatelessWidget {
const MultiSplitViewExampleApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MultiSplitViewExample(),
);
}
}
class MultiSplitViewExample extends StatefulWidget {
const MultiSplitViewExample({Key? key}) : super(key: key);
@override
MultiSplitViewExampleState createState() => MultiSplitViewExampleState();
}
class MultiSplitViewExampleState extends State<MultiSplitViewExample> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Multi Split View Example'), actions: [
ElevatedButton(onPressed: _clear, child: const Text('Clear'))
]),
body: MultiSplitViewTheme(
data: MultiSplitViewThemeData(
dividerPainter: DividerPainters.grooved2()),
child: MultiSplitView(controller: UI.to.controller)));
}
void _clear() {
UI.to.controller.areas = [];
}
}
Error
======== Exception caught by widgets library =======================================================
The following StateError was thrown building LayoutBuilder:
Bad state: No element
The relevant error-causing widget was:
LayoutBuilder LayoutBuilder:file:///cadu/multi_split_view/lib/src/multi_split_view.dart:175:12
When the exception was thrown, this was the stack:
dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 297:3 throw_
dart-sdk/lib/_internal/js_dev_runtime/private/js_array.dart 356:5 last]
packages/multi_split_view/src/internal/layout_constraints.dart 130:37 adjustAreas
I'll fix it.
Version 3.2.1 released.
Tks @cliftonlabrum!
Awesome, thank you!
I am setting up a
MultiSplitView
in aStatelessWidget
like this:And then over in a watch_it controller, I initialize my
Area
widgets like this:This results in an exception when my app launches:
The
desktop.dart:12
reference just points to my initializer:After I move past the exception, the split view renders correctly and works, but I'm trying to avoid having this error. Can I not initialize it via a controller like this? Any idea what I'm doing wrong?