Step 1: Static UI
home_screen.dart
class HomeScreenBody extends StatelessWidget {
SlideUpController slideUpController = SlideUpController();
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
child: Column(
children: [
RaisedButton(
child: Text('Slide up widget'),
onPressed: () {
},
)
],
),
),
SlideUpWidget()
],
);
}
}
slideup_widget.dart
import 'package:flutter/material.dart';
class SlideUpWidget extends StatefulWidget {
final SlideUpController controller;
const SlideUpWidget({Key key, this.controller}) : super(key: key);
@override
_SlideUpWidgetState createState() => _SlideUpWidgetState();
}
class _SlideUpWidgetState extends State<SlideUpWidget> {
@override
Widget build(BuildContext context) {
return Container(
height: 200,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
);
}
}

Step 2: Add action
I use Flutter provider (https://pub.dev/packages/provider) to handle the action.
slideup_widget.dart
import 'package:provider/provider.dart';
class SlideUpProvider with ChangeNotifier {
bool isShow = false;
void updateState(bool newState) {
isShow = newState;
notifyListeners();
}
}
I create a new simple controller to control the widget.
class SlideUpController {
SlideUpController._private();
static final SlideUpController instance = SlideUpController._private();
factory SlideUpController() => instance;
BuildContext _providerContext;
set providerContext(BuildContext context) {
if (_providerContext != context) {
_providerContext = context;
}
}
void toggle() {
if (_providerContext != null) {
final provider = _providerContext.read<SlideUpProvider>();
provider.updateState(!provider.isShow);
} else {
print('Need init provider context');
}
}
}
the _SlideUpWidgetState updated
class _SlideUpWidgetState extends State<SlideUpWidget> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => SlideUpProvider(),
child: Consumer<SlideUpProvider>(
builder: (context, provider, child) {
widget.controller?.providerContext = context;
return provider.isShow
? Container(
height: 200,
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20))),
)
: Container();
},
),
);
}
}
Add controller to home screen and trigger by button
class HomeScreenBody extends StatelessWidget {
SlideUpController slideUpController = SlideUpController();
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: [
Container(
child: Column(
children: [
RaisedButton(
child: Text('Slide up widget'),
onPressed: () {
slideUpController.toggle();
},
)
],
),
),
SlideUpWidget(
controller: slideUpController,
)
],
);
}
}

Step 3: Add slide animation
The scenario:
- Opacity for main ui
- Slide for SlideUpWidget
Update home_screen.dart
class HomeScreenBody extends StatefulWidget {
@override
_HomeScreenBodyState createState() => _HomeScreenBodyState();
}
class _HomeScreenBodyState extends State<HomeScreenBody>
with SingleTickerProviderStateMixin {
SlideUpController slideUpController = SlideUpController();
AnimationController _controller;
Animation<Offset> _offsetAnimation;
Animation<double> _fadeAnimation;
@override
void initState() {
super.initState();
_controller = AnimationController(
duration: const Duration(milliseconds: 350),
vsync: this,
);
_offsetAnimation = Tween<Offset>(
begin: const Offset(0, 1),
end: Offset.zero,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.decelerate,
))
..addStatusListener((status) {
if (status == AnimationStatus.forward) {
// Start animation at begin
slideUpController.toggle();
} else if (status == AnimationStatus.dismissed) {
// To hide widget, we need complete animation first
slideUpController.toggle();
}
});
_fadeAnimation = Tween<double>(
begin: 1,
end: 0,
).animate(CurvedAnimation(
parent: _controller,
curve: Curves.decelerate,
));
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Stack(
alignment: Alignment.bottomCenter,
children: [
FadeTransition(
opacity: _fadeAnimation,
child: Container(
height: double.infinity,
width: double.infinity,
color: Colors.grey,
child: RaisedButton(
child: Text('Slide up widget'),
onPressed: () {
if (_controller.isDismissed) {
_controller.forward();
} else {
_controller.reverse();
}
},
),
),
),
SlideTransition(
position: _offsetAnimation,
child: SlideUpWidget(
controller: slideUpController,
),
)
],
);
}
}