mc_gallery/lib/features/core/widgets/gap.dart

208 lines
4.7 KiB
Dart

import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
/// Const evenly-sized gap.
class Gap extends LeafRenderObjectWidget {
const Gap(
this.size, {
super.key,
});
final double size;
@override
RenderGap createRenderObject(BuildContext context) => RenderGap(size);
@override
void updateRenderObject(BuildContext context, covariant RenderGap renderObject) {
renderObject.gap = size;
super.updateRenderObject(context, renderObject);
}
static const size4 = Gap(4);
static const size8 = Gap(8);
static const size16 = Gap(16);
static const size24 = Gap(24);
static const size32 = Gap(32);
static const size64 = Gap(64);
}
class RenderGap extends RenderBox {
RenderGap(this._gap) : super() {
markNeedsLayout();
}
double _gap;
double get gap => _gap;
set gap(double value) {
if (_gap != value) {
_gap = value;
markNeedsLayout();
}
}
@override
void performLayout() {
final parent = this.parent;
Size newSize;
if (parent is RenderFlex) {
switch (parent.direction) {
case Axis.vertical:
newSize = Size(0, gap);
break;
case Axis.horizontal:
newSize = Size(gap, 0);
break;
}
} else {
newSize = Size.square(gap);
}
size = constraints.constrain(newSize);
}
}
/// Animates [Gap] insertion.
class AnimatedGap extends StatefulWidget {
const AnimatedGap(
this.gap, {
this.duration = const Duration(milliseconds: 200),
this.curve = Curves.easeInOut,
super.key,
});
final Duration duration;
final double gap;
final Curve curve;
@override
State<AnimatedGap> createState() => _AnimatedGapState();
}
class _AnimatedGapState extends State<AnimatedGap> with SingleTickerProviderStateMixin {
late final _controller = AnimationController(
vsync: this,
value: widget.gap,
upperBound: double.infinity,
);
@override
void didUpdateWidget(covariant AnimatedGap oldWidget) {
if (oldWidget.gap != widget.gap) {
_controller.animateTo(
widget.gap,
curve: widget.curve,
duration: widget.duration,
);
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<double>(
valueListenable: _controller,
builder: (context, gap, _) {
return Gap(gap);
},
);
}
}
class AnimatedSliverGap extends StatefulWidget {
const AnimatedSliverGap(
this.gap, {
this.duration = const Duration(milliseconds: 200),
this.curve = Curves.easeInOut,
super.key,
});
final Duration duration;
final double gap;
final Curve curve;
@override
State<AnimatedSliverGap> createState() => _AnimatedSliverGapState();
}
class _AnimatedSliverGapState extends State<AnimatedSliverGap> with SingleTickerProviderStateMixin {
late final _controller = AnimationController(
vsync: this,
value: widget.gap,
upperBound: double.infinity,
);
@override
void didUpdateWidget(covariant AnimatedSliverGap oldWidget) {
if (oldWidget.gap != widget.gap) {
_controller.animateTo(
widget.gap,
curve: widget.curve,
duration: widget.duration,
);
}
super.didUpdateWidget(oldWidget);
}
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<double>(
valueListenable: _controller,
builder: (context, gap, _) {
return SliverGap(gap);
},
);
}
}
class SliverGap extends LeafRenderObjectWidget {
const SliverGap(this.gap, {Key? key}) : super(key: key);
final double gap;
static const size4 = SliverGap(4);
static const size8 = SliverGap(8);
static const size16 = SliverGap(16);
static const size24 = SliverGap(24);
static const size32 = SliverGap(32);
static const size64 = SliverGap(64);
@override
RenderSliverGap createRenderObject(BuildContext context) => RenderSliverGap(gap);
@override
void updateRenderObject(BuildContext context, covariant RenderSliverGap renderObject) {
renderObject.gap = gap;
super.updateRenderObject(context, renderObject);
}
}
class RenderSliverGap extends RenderSliver {
RenderSliverGap(this._gap) : super() {
markNeedsLayout();
}
double _gap;
double get gap => _gap;
set gap(double value) {
if (_gap != value) {
_gap = value;
markNeedsLayout();
}
}
@override
void performLayout() {
final cacheExtent = calculateCacheOffset(constraints, from: 0, to: gap);
final paintExtent = calculatePaintOffset(constraints, from: 0, to: gap);
geometry = SliverGeometry(
paintExtent: paintExtent,
scrollExtent: gap,
visible: false,
cacheExtent: cacheExtent,
maxPaintExtent: gap,
);
}
}