You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

112 lines
2.6 KiB
Dart

import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
class AutoWrap extends StatefulWidget {
final List<Widget> children;
const AutoWrap({super.key, required this.children});
@override
State<StatefulWidget> createState() => _AutoWrapState();
}
class _AutoWrapState extends State<AutoWrap> {
var _computed = false;
var _isFirstBuild = true;
final Map<int, double> _childWidth = {};
var _isRow = true;
void handleSizeChange(Size size, int id) {
_childWidth[id] = size.width;
}
@override
void didUpdateWidget(covariant AutoWrap oldWidget) {
super.didUpdateWidget(oldWidget);
if (_isFirstBuild) {
_isFirstBuild = false;
var sum = _childWidth.values.reduce((value, element) => value + element);
var width = context.size?.width ?? 0;
setState(() {
_computed = true;
_isRow = sum < width;
});
}
}
@override
Widget build(BuildContext context) {
if (!_computed) {
List<Widget> stackChildren = [];
for (var i = 0; i < widget.children.length; i++) {
// Only first child is visible
stackChildren.add(
Opacity(
opacity: i == 0 ? 1 : 0,
child: WidgetSizeOffsetWrapper(
id: i,
onSizeChange: handleSizeChange,
child: widget.children[i],
),
),
);
}
return Stack(
children: stackChildren,
);
} else {
if (_isRow) {
return Row(children: widget.children);
} else {
return Column(children: widget.children);
}
}
}
}
typedef OnWidgetSizeChange = void Function(Size size, int id);
class WidgetSizeRenderObject extends RenderProxyBox {
final OnWidgetSizeChange onSizeChange;
final int id;
Size? currentSize;
WidgetSizeRenderObject(this.onSizeChange, this.id);
@override
void performLayout() {
super.performLayout();
try {
Size? newSize = child?.size;
if (newSize != null && currentSize != newSize) {
currentSize = newSize;
WidgetsBinding.instance.addPostFrameCallback((_) {
onSizeChange(newSize, id);
});
}
} catch (e) {
print(e);
}
}
}
class WidgetSizeOffsetWrapper extends SingleChildRenderObjectWidget {
final OnWidgetSizeChange onSizeChange;
final int id;
const WidgetSizeOffsetWrapper({
Key? key,
required this.onSizeChange,
required this.id,
required Widget child,
}) : super(key: key, child: child);
@override
RenderObject createRenderObject(BuildContext context) {
return WidgetSizeRenderObject(onSizeChange, id);
}
}