I'm currently having an issue animating an AnimatedPositioned widget inside a row widget. The widget does not size itself as it should and also throws an error. I imagine it has to do with the row not knowing the size of its child as animation occurs.
Currently the sidebar sizes correctly but i need that invisible box underneath to size as well for page content to be lapped properly.
When I collapse and show the sidebar I'm getting: Incorrect use of ParentDataWidget.
error.
I was looking at using AnimatedSize except wanted to check here if theres something simple I can change or do before going into this AnimatedSize change.
I would like the invisible box underneath my sidebar to animate just like my sidebar does. - code is copy/paste ready working example!
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: SafeArea(
child: Center(
child: MyWidget(),
),
),
),
);
}
}
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
@override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
bool showSidebar = true;
@override
Widget build(BuildContext context) {
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
return SafeArea(
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
Container(
width: double.maxFinite,
height: 700,
color: Colors.red,
),
Text(
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',
softWrap: true,
),
Container(
width: double.maxFinite,
height: 700,
color: Colors.yellow,
),
],
),
),
),
// Invisible box to allow space for sidebar when shown or hidden
// SizedBox(
// width: (showSidebar) ? 43 : 0,
// height: height, // Works but is too fast (instant)
// ),
AnimatedPositioned(
right: (showSidebar) ? 0 : -43,
curve: Curves.ease,
duration: const Duration(milliseconds: 100), // Does not work & throws error
child: SizedBox(
width: 43,
height: height,
),
),
],
),
// Sidebar box
AnimatedPositioned(
right: (showSidebar) ? 0 : -43,
curve: Curves.ease,
duration: const Duration(milliseconds: 100),
child: Container(
width: 43.0,
height: height,
color: Colors.blue,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: const [
SizedBox(height: 100.0),
Expanded(
child: Center(
child: RotatedBox(
quarterTurns: -1,
child: Text(
'EXAMPLE MENU BAR - PAGE 1',
style: TextStyle(
fontSize: 20.0, fontWeight: FontWeight.bold, color: Colors.white),
),
),
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.only(left: 5.0, top: 5.0, right: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
fakeButton(),
Column(
children: [
fakeButton(),
fakeButton(),
fakeButton(),
],
),
],
),
),
],
),
);
}
// Fake buttons
Widget fakeButton() {
return GestureDetector(
onTap: () => {
setState(() {
(showSidebar) ? showSidebar = false : showSidebar = true;
})
},
child: SizedBox(
height: 35,
width: 35,
child: Stack(
children: const [
Icon(
Icons.circle,
color: Colors.green,
size: 35.0,
),
Align(
alignment: Alignment.center,
child: Text(
'HIDE',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 9.0,
),
),
),
],
),
),
);
}
}
AnimatedPositioned
only works a child of Stack
. If the goal is for the row to move out of the way as the sidebar animates in you could wrap it in its own AnimatedPositioned
that shrinks as the sidebar moves:
return SafeArea(
child: Stack(
children: [
AnimatedPositioned(
top: 0,
bottom: 0,
left: 0,
right: (showSidebar) ? 43 : 0,
curve: Curves.ease,
duration: const Duration(milliseconds: 100),
child: Row(
// ...
AnimatedPadding
with padding applied only to the right would probably also work.