Skip to content

Commit

Permalink
Revert "ref: Improve layout and resize (#65)"
Browse files Browse the repository at this point in the history
This reverts commit 68da349.
  • Loading branch information
andyhorn committed Dec 19, 2024
1 parent 6a13f5c commit 6d2e1f2
Show file tree
Hide file tree
Showing 12 changed files with 381 additions and 858 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Set up Flutter
uses: kuhnroyal/flutter-fvm-config-action/setup@v3
uses: subosito/flutter-action@v2
with:
flutter-version: "3.22.1"
- name: Get packages
run: flutter pub get
- name: Analyze
Expand Down
3 changes: 0 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,3 @@ migrate_working_dir/
.dart_tool/
.packages
build/

# FVM Version Cache
.fvm/
14 changes: 0 additions & 14 deletions .vscode/launch.json

This file was deleted.

7 changes: 0 additions & 7 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
## 4.0.0-beta.1

- Rewrite the Controller/Container logic to allow Flutter to handle the initial layout of all widgets, updating the rendered sizes in the controller after the first frame. This _shouldn't_ have any major impact to the API, but it does introduce the use of Timers, which could affect tests.
- Rename `ResizableController.sizes` to `ResizableController.pixels` to more clearly indicate its value.
- Store, expose, and utilize the current list of `ResizableSize` values in the controller. This enables the values to be used even after manually updating them.


## 3.0.3

- Reinstate the removed `ResizableControllerManager#setChildren` method. This method was removed because the method it targets on the controller was made public. However, the package version was incorrectly bumped since this could be a breaking change. This patch reinstates the method, fixing the breaking change, but adds a deprecation warning in favor of the public controller method.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class _ControllerListenExampleScreenState
void initState() {
super.initState();
controller.addListener(() {
final sizes = controller.pixels;
final sizes = controller.sizes;
setState(() {
leftWidth = sizes.first;
rightWidth = sizes.last;
Expand Down
2 changes: 1 addition & 1 deletion example/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ packages:
path: ".."
relative: true
source: path
version: "4.0.0-beta.1"
version: "3.0.3"
flutter_test:
dependency: "direct dev"
description: flutter
Expand Down
2 changes: 1 addition & 1 deletion lib/flutter_resizable_container.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
library;
library flutter_resizable_container;

export 'src/resizable_container.dart';
export 'src/resizable_controller.dart' show ResizableController;
Expand Down
261 changes: 91 additions & 170 deletions lib/src/resizable_container.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import 'dart:async';
import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_resizable_container/flutter_resizable_container.dart';
import 'package:flutter_resizable_container/src/extensions/box_constraints_ext.dart';
import 'package:flutter_resizable_container/src/extensions/iterable_ext.dart';
import 'package:flutter_resizable_container/src/resizable_container_divider.dart';
import 'package:flutter_resizable_container/src/resizable_controller.dart';

Expand Down Expand Up @@ -46,12 +46,13 @@ class _ResizableContainerState extends State<ResizableContainer> {
late final controller = widget.controller ?? ResizableController();
late final isDefaultController = widget.controller == null;
late final manager = ResizableControllerManager(controller);
late var keys = _generateKeys();
late List<GlobalKey> keys = List.generate(
widget.children.length,
(_) => GlobalKey(),
);

List<GlobalKey> _generateKeys() => List.generate(
widget.children.length,
(_) => GlobalKey(),
);
var initialized = false;
var initScheduled = false;

@override
void initState() {
Expand All @@ -62,16 +63,15 @@ class _ResizableContainerState extends State<ResizableContainer> {

@override
void didUpdateWidget(covariant ResizableContainer oldWidget) {
final didChildrenChange = !listEquals(oldWidget.children, widget.children);
final didDirectionChange = widget.direction != oldWidget.direction;
final hasChanges = didChildrenChange || didDirectionChange;

if (didChildrenChange) {
controller.setChildren(widget.children);
}
final hasChanges = !listEquals(oldWidget.children, widget.children)
|| oldWidget.direction != widget.direction;

if (hasChanges) {
keys = _generateKeys();
manager.updateChildren(widget.children);
keys = List.generate(
widget.children.length,
(_) => GlobalKey(),
);
}

super.didUpdateWidget(oldWidget);
Expand All @@ -96,62 +96,82 @@ class _ResizableContainerState extends State<ResizableContainer> {
return AnimatedBuilder(
animation: controller,
builder: (context, _) {
if (controller.needsLayout) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_readSizesAfterLayout();
});

return PreLayout(
availableSpace: availableSpace,
children: widget.children,
direction: widget.direction,
divider: widget.divider,
keys: keys,
sizes: controller.sizes,
);
} else {
return Flex(
crossAxisAlignment: CrossAxisAlignment.stretch,
direction: widget.direction,
children: [
for (var i = 0; i < widget.children.length; i++) ...[
Builder(
builder: (context) {
final child = widget.children[i].child;

final height = _getChildSize(
index: i,
direction: Axis.vertical,
constraints: constraints,
);
final hasFlexOrShrink = widget.children.any(
(child) => child.size.isShrink || child.size.isExpand,
);

final width = _getChildSize(
index: i,
direction: Axis.horizontal,
constraints: constraints,
return Flex(
crossAxisAlignment: CrossAxisAlignment.stretch,
direction: widget.direction,
children: [
for (var i = 0; i < widget.children.length; i++) ...[
Builder(
builder: (context) {
final child = widget.children[i].child;
final size = widget.children[i].size;
final key = keys[i];

final scheduleInit = hasFlexOrShrink && !initScheduled;
final shrink = !initialized && size.isShrink;
final expand = !initialized && size.isExpand;

if (scheduleInit) {
Timer.run(_sizeInit);
initScheduled = true;
}

if (shrink) {
// Use UnconstrainedBox to allow the child to shrink
// to its minimum size.
return UnconstrainedBox(
key: key,
child: child,
);

return SizedBox(
height: height,
width: width,
}

if (expand) {
// Use Expanded to allow the child to expand to fill
// the available space, mediated by its "flex" value.
return Expanded(
key: key,
flex: size.value.toInt(),
child: child,
);
},
),
if (i < widget.children.length - 1) ...[
ResizableContainerDivider(
config: widget.divider,
direction: widget.direction,
onResizeUpdate: (delta) => manager.adjustChildSize(
index: i,
delta: delta,
),
}

final height = _getChildSize(
index: i,
direction: Axis.vertical,
constraints: constraints,
);

final width = _getChildSize(
index: i,
direction: Axis.horizontal,
constraints: constraints,
);

return SizedBox(
key: key,
height: height,
width: width,
child: child,
);
},
),
if (i < widget.children.length - 1) ...[
ResizableContainerDivider(
config: widget.divider,
direction: widget.direction,
onResizeUpdate: (delta) => manager.adjustChildSize(
index: i,
delta: delta,
),
],
),
],
],
);
}
],
);
},
);
},
Expand All @@ -174,11 +194,15 @@ class _ResizableContainerState extends State<ResizableContainer> {
if (direction != direction) {
return constraints.maxForDirection(direction);
} else {
return controller.pixels[index];
var size = controller.sizes[index];
final child = widget.children[index];
size = min(size, child.maxSize ?? double.infinity);
size = max(size, child.minSize ?? 0);
return size;
}
}

void _readSizesAfterLayout() {
void _sizeInit() {
final sizes = keys.map<double>((key) {
final size = _getRenderBoxSize(key);

Expand All @@ -192,115 +216,12 @@ class _ResizableContainerState extends State<ResizableContainer> {
};
});

manager.setRenderedSizes(sizes.toList());
manager.setSizes(sizes.toList());
initialized = true;
}

Size? _getRenderBoxSize(GlobalKey key) {
final renderBox = key.currentContext?.findRenderObject() as RenderBox?;
return renderBox?.size;
}
}

class PreLayout extends StatelessWidget {
const PreLayout({
super.key,
required this.availableSpace,
required this.children,
required this.direction,
required this.divider,
required this.keys,
required this.sizes,
});

final double availableSpace;
final List<ResizableChild> children;
final Axis direction;
final ResizableDivider divider;
final List<GlobalKey> keys;
final List<ResizableSize> sizes;

@override
Widget build(BuildContext context) {
final totalPixels =
sizes.where((size) => size.isPixels).sum((size) => size.value);

return Flex(
crossAxisAlignment: CrossAxisAlignment.stretch,
direction: direction,
children: [
for (var i = 0; i < children.length; i++) ...[
Builder(builder: (context) {
final size = sizes[i];
final value = size.value;

if (size.isPixels) {
final constrained = _getConstrainedSize(
value: value,
minimum: children[i].minSize,
maximum: children[i].maxSize,
);

return SizedBox(
key: keys[i],
height: direction == Axis.horizontal ? null : constrained,
width: direction == Axis.horizontal ? constrained : null,
child: children[i].child,
);
}

if (size.isRatio) {
final size = (availableSpace - totalPixels) * value;
final constrained = _getConstrainedSize(
value: size,
minimum: children[i].minSize,
maximum: children[i].maxSize,
);

return SizedBox(
key: keys[i],
height: direction == Axis.horizontal ? null : constrained,
width: direction == Axis.horizontal ? constrained : null,
child: children[i].child,
);
}

if (size.isShrink) {
return UnconstrainedBox(
key: keys[i],
child: children[i].child,
);
}

return Expanded(
key: keys[i],
flex: value.toInt(),
child: children[i].child,
);
}),
if (i < children.length - 1) ...[
ResizableContainerDivider(
config: divider,
direction: direction,
onResizeUpdate: (_) {},
),
],
],
],
);
}

double _getConstrainedSize({
required double value,
required double? minimum,
required double? maximum,
}) {
if (minimum == null && maximum == null) {
return value;
}

var adjustedSize = min(value, maximum ?? double.infinity);
adjustedSize = max(adjustedSize, 0);

return adjustedSize;
}
}
Loading

0 comments on commit 6d2e1f2

Please sign in to comment.