🚀
【Flutter】独自SnackBarで位置を上!margin使わないから画面タップに影響なし
通常のSnackBarでは、SnackBarをmarginで上部に表示中は画面タップが効かなくなります。
void showSnackBar({
required BuildContext context,
required String message,
}) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'SnackBarを表示します',
style: ...省略
),
duration: const Duration(seconds: 1),
backgroundColor: const Color(0xFF333333).withOpacity(0.8),
behavior: SnackBarBehavior.floating,
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13),
margin: EdgeInsets.only(
bottom: MediaQuery.of(context).size.height - 150, // ここで無理やり上にしている
left: 16,
right: 16,
),
),
);
}
そこで、Overlayを使って、SnackBarを再現してPositionで浮かせることで解決できます。
void showSnackBar({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 1),
}) {
final overlay = Overlay.of(context);
final overlayEntry = OverlayEntry(
builder: (context) => Positioned(
top: 70,
left: 16,
right: 16,
child: Material(
color: Colors.transparent,
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13),
decoration: BoxDecoration(
color: const Color(0xFF333333).withOpacity(0.8),
borderRadius: BorderRadius.circular(5),
boxShadow: const [
BoxShadow(
color: Colors.black26,
offset: Offset(0, 5),
blurRadius: 5,
spreadRadius: 1,
),
],
),
child: Text(
message,
style: ...省略,
),
),
),
),
);
overlay.insert(overlayEntry);
Future.delayed(duration, () => overlayEntry.remove());
}
ちなみにDismissible
を使うことで、SnackBar表示後に上にスワイプして消すことも再現できます。
void showSnackBar({
required BuildContext context,
required String message,
Duration duration = const Duration(seconds: 100),
}) {
final overlay = Overlay.of(context);
late OverlayEntry overlayEntry;
overlayEntry = OverlayEntry(
builder: (context) => Positioned(
top: 70,
left: 16,
right: 16,
child: Material(
color: Colors.transparent,
child: Dismissible(
direction: DismissDirection.up,
onDismissed: (direction) => overlayEntry.remove(),
key: ValueKey(message),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 13),
decoration: BoxDecoration(
color: const Color(0xFF333333).withOpacity(0.8),
borderRadius: BorderRadius.circular(5),
boxShadow: const [
BoxShadow(
color: Colors.black26,
offset: Offset(0, 5),
blurRadius: 5,
spreadRadius: 1,
),
],
),
child: Text(
message,
style: ...省略,
),
),
),
),
),
);
overlay.insert(overlayEntry);
Future.delayed(duration, () => overlayEntry.remove());
}
Discussion