caduandrade / multi_split_view

Provides horizontal or vertical multiple split view for Flutter.
MIT License
152 stars 29 forks source link

Allow changing area programmatically #68

Closed Sten435 closed 3 months ago

Sten435 commented 3 months ago

Add an option to change the size of flex using a controller, for example double tap on a divider should reset the position to the first position.

This is kinda basic, kinda weird something this simple is not already implemented ?

Sten435 commented 3 months ago
    return MultiSplitView(
      controller: controller1,
      onDividerDoubleTap: (dividerIndex) {
        controller1.getArea(dividerIndex).setFlex(2);
        controller1.getArea(dividerIndex).setSize(150);
      },
      dividerBuilder: (axis, index, resizable, dragging, highlighted, themeData) {
        return const VerticalDivider(indent: 0, endIndent: 0, width: 0, thickness: 0);
      },
    );
Sten435 commented 3 months ago

You should make the AreaHelper public

@internal
class AreaHelper {
  static Key keyFrom({required Area area}) {
    return area._key;
  }

  /// Sets the area flex value.
  static void setFlex({required Area area, required double flex}) {
    flex = NumUtil.fix('flex', flex);
    if (area.min != null) {
      flex = math.max(flex, area.min!);
    }
    area._flex = flex;
  }

  /// Sets the area size value.
  static void setSize({required Area area, required double? size}) {
    if (size != null) {
      size = NumUtil.fix('size', size);
    }
    area._size = size;
  }

  /// Sets the area min value.
  static void setMin({required Area area, required double? min}) {
    if (min != null) {
      min = math.max(0, min);
    }
    area._min = min;
  }

  /// Sets the area max value.
  static void setMax({required Area area, required double? max}) {
    area._max = max;
  }

  /// Sets the area index.
  static void setIndex({required Area area, required int index}) {
    area._index = index;
  }
}
Sten435 commented 3 months ago

I dont want to trigger the initState of my widgets when i want to programaticly change them.

Sten435 commented 3 months ago

@caduandrade https://github.com/caduandrade/multi_split_view/pull/69

caduandrade commented 3 months ago

Hi @Sten435!

You cannot directly change the flex in the Area class as this would make the layout inconsistent. But you can change it through the controller, you can define the areas in it:

controller.areas = [...]

Sorry, I didn't understand your problem with the initState of your Widgets. I believe that in this case, you did something wrong, forcing the creation of a new state. Flutter is very efficient at recreating widgets and reusing states.

An example of inconsistency: the user could set all areas to flex 0.

The algorithm that adjusts inconsistency is executed only when setting the areas for performance reasons.

I think that in your proposal, there shouldn't even be Helpers. It should allow changing values ​​directly in the Area class. But it would be important to perform the inconsistency adjustment efficiently. (know how to execute only when there is a change?). And of course think about all the cases where perhaps you should throw an exception.

I'm going to think if there could be a flag to mark that the area has been changed. So in the build, the incostence algorithm would not always execute.

Sten435 commented 3 months ago

Hi @Sten435!

You cannot directly change the flex in the Area class as this would make the layout inconsistent. But you can change it through the controller, you can define the areas in it:


controller.areas = [...]

Sorry, I didn't understand your problem with the initState of your Widgets. I believe that in this case, you did something wrong, forcing the creation of a new state. Flutter is very efficient at recreating widgets and reusing states.

An example of inconsistency: the user could set all areas to flex 0.

The algorithm that adjusts inconsistency is executed only when setting the areas for performance reasons.

I think that in your proposal, there shouldn't even be Helpers. It should allow changing values ​​directly in the Area class. But it would be important to perform the inconsistency adjustment efficiently. (know how to execute only when there is a change?). And of course think about all the cases where perhaps you should throw an exception.

I'm going to think if there could be a flag to mark that the area has been changed. So in the build, the incostence algorithm would not always execute.

Hey @caduandrade 👋

For example

When you have 2 areas.

void update() {
controller.area = [
Area(
   flex: 2,
   builder: ()=> StatefulWidget(),
),

Area(
   flex: 1,
   builder: ()=> StatefulWidgetSecond(),
),
];
}

When i call update() the initState method from the statefullwidgets are both called 😯.

This is not expected behavior.

This can be fixed by my example e.g. my pull request.

Or give the users the ability to add a 'Key' e.g. ValueKey(...) to the area. This would also fix the issue.

The reason the initState is triggered, is because you create a UniqueKey() in the area. And that will always trigger the initState function. 🙃

caduandrade commented 3 months ago

Hi @Sten435!

Now I understand your initState problem. The UniqueKey is necessary for the area because if the number of areas changes, Flutter also resets the state because its tree structure changes. But in your case, as you instantiated a new area, you also created a new UniqueKey

To make your life even more difficult, the Area's builder does not have the key to reuse it.

I will check the following points: 1) If there is any problem with allowing reuse. 2) If it is possible to clone the Area by changing some values. 3) Change the values ​​directly in the Area.

Even if you don't use them all, they are valid.

Sten435 commented 3 months ago

Hi @Sten435!

Now I understand your initState problem. The UniqueKey is necessary for the area because if the number of areas changes, Flutter also resets the state because its tree structure changes. But in your case, as you instantiated a new area, you also created a new UniqueKey

To make your life even more difficult, the Area's builder does not have the key to reuse it.

I will check the following points:

1) If there is any problem with allowing reuse.

2) If it is possible to clone the Area by changing some values.

3) Change the values ​​directly in the Area.

Even if you don't use them all, they are valid.

Hey @caduandrade 👋

I don't quite understand your last words: Even if you don't use them all, they are valid.?

What do you mean with this?

Could you also explain why tou cannot simply reuse the same key?

And why a user can't just give a key to the area?

caduandrade commented 3 months ago

Hi @Sten435 !

Just with this change committed you can change the areas by reusing the same id. I replaced the internal key with the id.

I will think about the cost/benefit of changing values ​​directly in the Area. To do this, it is also necessary to decide whether a single change would notify the widget or whether it should be done within a setState.

Sten435 commented 3 months ago

Hi @Sten435 !

Just with this change committed you can change the areas by reusing the same id. I replaced the internal key with the id.

I will think about the cost/benefit of changing values ​​directly in the Area. To do this, it is also necessary to decide whether a single change would notify the widget or whether it should be done within a setState.

Hey 👋 @caduandrade

Thanks for the fast response.

Could you also update pub dev? I saw that the latest update was over 30d ago.

Big thanks for the change.

caduandrade commented 3 months ago

Version 3.2.0 released.

Now you can reuse the id to build the new areas ok?