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.
160 lines
3.9 KiB
Dart
160 lines
3.9 KiB
Dart
import 'package:flutter/rendering.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
|
|
class ResponsivePair extends StatefulWidget {
|
|
final List<Widget> children;
|
|
final MainAxisAlignment rowMainAxisAlignment;
|
|
final CrossAxisAlignment rowCrossAxisAlignment;
|
|
|
|
final MainAxisAlignment colMainAxisAlignment;
|
|
final CrossAxisAlignment colCrossAxisAlignment;
|
|
|
|
const ResponsivePair({
|
|
super.key,
|
|
required this.children,
|
|
this.rowMainAxisAlignment = MainAxisAlignment.spaceBetween,
|
|
this.rowCrossAxisAlignment = CrossAxisAlignment.center,
|
|
this.colMainAxisAlignment = MainAxisAlignment.spaceBetween,
|
|
this.colCrossAxisAlignment = CrossAxisAlignment.start,
|
|
});
|
|
|
|
@override
|
|
State<StatefulWidget> createState() => _ResponsivePairState();
|
|
}
|
|
|
|
class _ResponsivePairState extends State<ResponsivePair> {
|
|
var _computed = false;
|
|
final Map<int, double> _childWidth = {};
|
|
var _isRow = true;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
}
|
|
|
|
void refreshSize() {
|
|
if (_childWidth.length != widget.children.length) return;
|
|
|
|
var sum = _childWidth.values.reduce((value, element) => value + element);
|
|
var width = context.size?.width ?? 0;
|
|
|
|
setState(() {
|
|
_computed = true;
|
|
_isRow = sum < width;
|
|
});
|
|
}
|
|
|
|
void handleSizeChange(Size size, int id) {
|
|
_childWidth[id] = size.width;
|
|
if (_childWidth.length == widget.children.length) {
|
|
refreshSize();
|
|
}
|
|
}
|
|
|
|
@override
|
|
void didChangeDependencies() {
|
|
super.didChangeDependencies();
|
|
|
|
setState(() {
|
|
_computed = false;
|
|
});
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
Widget inner;
|
|
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],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
inner = Stack(
|
|
children: stackChildren,
|
|
);
|
|
} else {
|
|
if (_isRow) {
|
|
var i = -1;
|
|
var children = widget.children.map((child) {
|
|
i++;
|
|
if (i != 0) {
|
|
return Flexible(child: child);
|
|
}
|
|
return child;
|
|
}).toList();
|
|
inner = Row(
|
|
mainAxisAlignment: widget.rowMainAxisAlignment,
|
|
crossAxisAlignment: widget.rowCrossAxisAlignment,
|
|
children: children,
|
|
);
|
|
} else {
|
|
inner = Column(
|
|
mainAxisAlignment: widget.colMainAxisAlignment,
|
|
crossAxisAlignment: widget.colCrossAxisAlignment,
|
|
children: widget.children,
|
|
);
|
|
}
|
|
}
|
|
return AnimatedSize(
|
|
duration: const Duration(milliseconds: 150),
|
|
curve: Curves.linear,
|
|
alignment: Alignment.topCenter,
|
|
child: inner,
|
|
);
|
|
}
|
|
}
|
|
|
|
typedef WidgetSizeChangeCallback = void Function(Size size, int id);
|
|
|
|
class WidgetSizeRenderObject extends RenderProxyBox {
|
|
final WidgetSizeChangeCallback 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, stack) {
|
|
debugPrint("$e $stack");
|
|
}
|
|
}
|
|
}
|
|
|
|
class WidgetSizeOffsetWrapper extends SingleChildRenderObjectWidget {
|
|
final WidgetSizeChangeCallback 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);
|
|
}
|
|
}
|