Skip to content

Instantly share code, notes, and snippets.

@clragon
Created December 11, 2023 11:45
Show Gist options
  • Select an option

  • Save clragon/e76404d3a32a48cd814afccf03be1583 to your computer and use it in GitHub Desktop.

Select an option

Save clragon/e76404d3a32a48cd814afccf03be1583 to your computer and use it in GitHub Desktop.
widget swapper
import 'dart:math';
import 'package:boxy/boxy.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const App());
}
class App extends StatelessWidget {
const App({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true,
),
home: const Home(),
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool swapped = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: const Text('Widget Swap Demo'),
),
body: Center(
child: WidgetSwapper(
top: Container(
height: 200,
width: 300,
color: Colors.red.withOpacity(0.5),
child: const Center(
child: Text('Top'),
),
),
bottom: Container(
height: 400,
width: 300,
color: Colors.blue.withOpacity(0.5),
child: const Center(
child: Text('Bottom'),
),
),
swapped: swapped,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => setState(() => swapped = !swapped),
tooltip: 'Swap',
child: const Icon(Icons.swap_horiz),
),
);
}
}
class WidgetSwapper extends StatelessWidget {
const WidgetSwapper({
super.key,
required this.top,
required this.bottom,
this.swapped = false,
this.duration = const Duration(milliseconds: 300),
});
final Widget top;
final Widget bottom;
final bool swapped;
final Duration duration;
@override
Widget build(BuildContext context) {
return TweenAnimationBuilder<double>(
duration: duration,
curve: Curves.easeInOut,
tween: Tween<double>(
begin: swapped ? 1 : 0,
end: swapped ? 1 : 0,
),
builder: (context, value, child) => CustomBoxy(
delegate: SwapperBoxyDelegate(
progress: value,
),
children: [
BoxyId(
id: #top,
child: top,
),
BoxyId(
id: #bottom,
child: bottom,
),
],
),
);
}
}
class SwapperBoxyDelegate extends BoxyDelegate {
SwapperBoxyDelegate({required this.progress});
final double progress;
@override
bool shouldRelayout(covariant SwapperBoxyDelegate oldDelegate) =>
oldDelegate.progress != progress;
@override
Size layout() {
final top = getChild(#top);
final bottom = getChild(#bottom);
final topSize = top.layout(constraints);
final bottomSize = bottom.layout(constraints);
final height = topSize.height + bottomSize.height;
final width = max(topSize.width, bottomSize.width);
final topLeftOver = bottomSize.height * progress;
final bottomLeftOver = topSize.height * (1 - progress);
top.position(
Offset(
0,
topLeftOver,
),
);
bottom.position(
Offset(
0,
bottomLeftOver,
),
);
return Size(width, height);
}
@override
double maxIntrinsicWidth(double height) {
final top = getChild(#top);
final bottom = getChild(#bottom);
return max(
top.render.getMaxIntrinsicWidth(height),
bottom.render.getMaxIntrinsicWidth(height),
);
}
@override
double maxIntrinsicHeight(double width) {
final top = getChild(#top);
final bottom = getChild(#bottom);
return top.render.getMaxIntrinsicHeight(width) +
bottom.render.getMaxIntrinsicHeight(width);
}
@override
double minIntrinsicHeight(double width) {
final top = getChild(#top);
final bottom = getChild(#bottom);
return top.render.getMinIntrinsicHeight(width) +
bottom.render.getMinIntrinsicHeight(width);
}
@override
double minIntrinsicWidth(double height) {
final top = getChild(#top);
final bottom = getChild(#bottom);
return max(
top.render.getMinIntrinsicWidth(height),
bottom.render.getMinIntrinsicWidth(height),
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment