将 FAB 转换为模态底部 sheet(或类似)
Transform FAB to modal bottom sheet (or similar)
我正在尝试使 FAB 展开成为底部 sheet,类似于 material.io
中的“屏幕内”示例
所以当我点击
this FAB
动画成为
this modal bottom sheet
下面是这个例子的代码:
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Center(child: Text('Hello, World!')),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () async {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
barrierColor: Colors.transparent,
builder: (context) {
return AddEntryBottomSheet();
},
);
},
),
);
}
}
class AddEntryBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(32.0),
child: Text('Hello, world!'),
),
Padding(
padding: const EdgeInsets.all(32.0),
child: Text('More content'),
),
],
),
);
}
}
我设法通过下面的示例获得了我想要的结果。只需将 ExpandingFab 用作脚手架中的 FAB
import 'package:flutter/material.dart';
class ExpandingFab extends StatefulWidget {
@override
_ExpandingFabState createState() => _ExpandingFabState();
}
class _ExpandingFabState extends State<ExpandingFab> {
bool _cardIsOpen = false;
double get cardWidth => MediaQuery.of(context).size.width - 32;
double cardHeight = 200;
Widget _renderFab() {
return InkWell(
onTap: () {
setState(() {
_cardIsOpen = true;
});
},
child: Icon(Icons.add, color: Colors.white),
);
}
Widget _renderUpsertEntryCard() {
return Container(
width: cardWidth,
height: cardHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Hello, World!'),
ElevatedButton(
onPressed: () {
setState(() {
_cardIsOpen = false;
});
},
child: Text('Close'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
double w = _cardIsOpen ? cardWidth : 56;
double h = _cardIsOpen ? cardHeight : 56;
return AnimatedContainer(
curve: Curves.ease,
constraints: BoxConstraints(
minWidth: w, maxWidth: w,
minHeight: h, maxHeight: h,
),
duration: Duration(milliseconds: 300),
decoration: BoxDecoration(
color: _cardIsOpen ? Colors.blueGrey[100] : Colors.blue,
boxShadow: kElevationToShadow[1],
borderRadius: _cardIsOpen
? BorderRadius.all(Radius.circular(0.0))
: BorderRadius.all(Radius.circular(50)),
),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 200),
transitionBuilder: (child, animation) => ScaleTransition(
scale: animation,
child: child,
),
child: !_cardIsOpen ? _renderFab() : _renderUpsertEntryCard(),
),
);
}
}
我正在尝试使 FAB 展开成为底部 sheet,类似于 material.io
中的“屏幕内”示例所以当我点击 this FAB 动画成为 this modal bottom sheet
下面是这个例子的代码:
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Example'),
),
body: Center(child: Text('Hello, World!')),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () async {
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
barrierColor: Colors.transparent,
builder: (context) {
return AddEntryBottomSheet();
},
);
},
),
);
}
}
class AddEntryBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Card(
margin: EdgeInsets.all(8.0),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.all(32.0),
child: Text('Hello, world!'),
),
Padding(
padding: const EdgeInsets.all(32.0),
child: Text('More content'),
),
],
),
);
}
}
我设法通过下面的示例获得了我想要的结果。只需将 ExpandingFab 用作脚手架中的 FAB
import 'package:flutter/material.dart';
class ExpandingFab extends StatefulWidget {
@override
_ExpandingFabState createState() => _ExpandingFabState();
}
class _ExpandingFabState extends State<ExpandingFab> {
bool _cardIsOpen = false;
double get cardWidth => MediaQuery.of(context).size.width - 32;
double cardHeight = 200;
Widget _renderFab() {
return InkWell(
onTap: () {
setState(() {
_cardIsOpen = true;
});
},
child: Icon(Icons.add, color: Colors.white),
);
}
Widget _renderUpsertEntryCard() {
return Container(
width: cardWidth,
height: cardHeight,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text('Hello, World!'),
ElevatedButton(
onPressed: () {
setState(() {
_cardIsOpen = false;
});
},
child: Text('Close'),
),
],
),
);
}
@override
Widget build(BuildContext context) {
double w = _cardIsOpen ? cardWidth : 56;
double h = _cardIsOpen ? cardHeight : 56;
return AnimatedContainer(
curve: Curves.ease,
constraints: BoxConstraints(
minWidth: w, maxWidth: w,
minHeight: h, maxHeight: h,
),
duration: Duration(milliseconds: 300),
decoration: BoxDecoration(
color: _cardIsOpen ? Colors.blueGrey[100] : Colors.blue,
boxShadow: kElevationToShadow[1],
borderRadius: _cardIsOpen
? BorderRadius.all(Radius.circular(0.0))
: BorderRadius.all(Radius.circular(50)),
),
child: AnimatedSwitcher(
duration: Duration(milliseconds: 200),
transitionBuilder: (child, animation) => ScaleTransition(
scale: animation,
child: child,
),
child: !_cardIsOpen ? _renderFab() : _renderUpsertEntryCard(),
),
);
}
}