我将 FAB 实现为可扩展的,当单击 FAB 时,带有一点黑色覆盖。 我的问题是脚手架中有右边距,而我的叠加层没有填充整个视图。
如何删除右边距?
它的样子是这样的:
这是我的脚手架代码:
return Scaffold(
resizeToAvoidBottomInset: true,
floatingActionButton: !isSearchBarVisible ? SizedBox.expand(
child: ExpandableFab(
//key: _key,
distance: size.height * 0.09,
children: [
/* not needed to show problem */
],
),
) : null,
body: /* some body */
这是 ExpandableFab 类
class ExpandableFab extends StatefulWidget {
const ExpandableFab({
Key? key,
this.initialOpen,
required this.distance,
required this.children,
}) : super(key: key);
final bool? initialOpen;
final double distance;
final List<Widget> children;
@override
_ExpandableFabState createState() => _ExpandableFabState();
}
class _ExpandableFabState extends State<ExpandableFab>
with SingleTickerProviderStateMixin {
late AnimationController _controller;
Animation<double>? _expandAnimation;
bool _open = false;
@override
void initState() {
super.initState();
_open = widget.initialOpen ?? false;
_controller = AnimationController(
value: _open ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
vsync: this,
);
_expandAnimation = CurvedAnimation(
curve: Curves.fastOutSlowIn,
reverseCurve: Curves.easeOutQuad,
parent: _controller,
);
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void _toggle() {
setState(() {
_open = !_open;
if (_open) {
_controller.forward();
} else {
_controller.reverse();
}
});
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return GestureDetector(
onTap: () => _toggle(),
child: Stack(
alignment: Alignment.bottomRight,
clipBehavior: Clip.none,
children: [
IgnorePointer(
ignoring: !_open,
child: TweenAnimationBuilder<double>(
tween: Tween<double>(begin: 0.0, end: _open ? 1.0 : 0.0),
duration: Duration(milliseconds: 500),
curve: Curves.easeInOut,
builder: (_, value, child) {
if (value < 0.001) {
return child!;
}
return BackdropFilter(
filter: ImageFilter.blur(sigmaX: value, sigmaY: value),
child: child,
);
},
child: Container(color: Colors.transparent),
),
),
IgnorePointer(
ignoring: !_open,
child: AnimatedOpacity(
duration: Duration(milliseconds: 500),
opacity: _open ? 1 : 0,
curve: Curves.easeInOut,
child: Container(
color: Colors.black12,
),
),
),
Transform.translate(
offset: Offset(0, 0),
child: Stack(
alignment: Alignment.bottomRight,
children: [
Positioned(
bottom: size.height * 0.14,
child: _buildTapToCloseFab(size)
),
Positioned(
bottom: size.height * 0.14,
child: _buildTapToOpenFab(size)
),
..._buildExpandingActionButtons(),
],
),
),
],
),
);
}
Widget _buildTapToCloseFab(Size size) {
return SizedBox(
width: 56.0,
height: 56.0,
child: Center(
child: Material(
shape: const CircleBorder(),
clipBehavior: Clip.antiAlias,
elevation: 4.0,
child: InkWell(
onTap: _toggle,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(
Icons.close,
color: Theme.of(context).primaryColor,
),
),
),
),
),
);
}
Widget _buildTapToOpenFab(Size size) {
return IgnorePointer(
ignoring: _open,
child: AnimatedContainer(
transformAlignment: Alignment.center,
transform: Matrix4.diagonal3Values(
_open ? 0.7 : 1.0,
_open ? 0.7 : 1.0,
1.0,
),
duration: const Duration(milliseconds: 250),
curve: const Interval(0.0, 0.5, curve: Curves.easeOut),
child: AnimatedOpacity(
opacity: _open ? 0.0 : 1.0,
curve: const Interval(0.25, 1.0, curve: Curves.easeInOut),
duration: const Duration(milliseconds: 250),
child: FloatingActionButton(
onPressed: _toggle,
child: Icon(
Icons.add,
),
),
),
),
);
}
List<Widget> _buildExpandingActionButtons() {
final children = <Widget>[];
final count = widget.children.length;
final step = 90.0 / (count - 1);
var dist;
for (var i = 0, angleInDegrees = 0.0;
i < count;
i++, angleInDegrees += step) {
if (i == 0) {
dist = (widget.distance) * (i + 1);
}
else {
dist = (widget.distance) * (i + 1);
}
children.add(
_ExpandingActionButton(
directionInDegrees: 90,
maxDistance: dist,
progress: _expandAnimation,
child: widget.children[i],
),
);
}
return children;
}
}
class _ExpandingActionButton extends StatelessWidget {
const _ExpandingActionButton({
Key? key,
required this.directionInDegrees,
required this.maxDistance,
required this.progress,
required this.child,
}) : super(key: key);
final double directionInDegrees;
final double maxDistance;
final Animation<double>? progress;
final Widget child;
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return AnimatedBuilder(
animation: progress!,
builder: (BuildContext context, Widget? child) {
final offset = Offset.fromDirection(
directionInDegrees * (math.pi / 180.0),
progress!.value * maxDistance,
);
return Positioned(
right: 4.0 + offset.dx,
bottom: (size.height * 0.14) + 4.0 + offset.dy,
child: Transform.rotate(
angle: (1.0 - progress!.value) * math.pi / 2,
child: child,
),
);
},
child: FadeTransition(
opacity: progress!,
child: child,
),
);
}
}
主要是 Flutter 教程中的代码:https://docs.flutter.dev/cookbook/effects/expandable-fab,有一些小的更改,例如 FAB 展开时垂直展开或覆盖。
使用这个结构:
Scaffold(
resizeToAvoidBottomInset: true,
floatingActionButton: !isSearchBarVisible ? Padding(
padding: const EdgeInsets.all(8.0),
child: SizedBox.expand(
child: ExpandableFab(
//key: _key,
distance: size.height * 0.09,
children: [
/* not needed to show problem */
],
),
),
) : null,
body: