こんな感じで、BottomNavigationBar に FloatingActionButton を埋め込んでみた。
FloatingActionButton は丸くして、ぼわっと縁取ったカスタム仕様。
コード
カスタマイズした FloatingActionButton
まずは少しカッコよく見える、以下の特徴を持つ FloatingActionButton を作った。
- 円形である。
- ぼわっとした縁取り。
import 'package:flutter/material.dart';
/// ぼわぁっとした縁取りを持つ円形の FAB.
class BlurCircleFloatingActionButton extends StatelessWidget {
final VoidCallback onPressed;
final Widget child;
final Color backgroundColor;
final Color borderColor;
final Color shadowColor;
final double borderWidth;
final double blurRadius;
final double spreadRadius;
final double width;
final double height;
const BlurCircleFloatingActionButton({super.key,
required this.onPressed,
required this.child,
required this.backgroundColor,
required this.borderColor,
required this.shadowColor,
this.borderWidth = 2.0,
this.blurRadius = 10,
this.spreadRadius = 5,
this.width = 36.0,
this.height = 36.0,
});
@override
Widget build(BuildContext context) {
return Container(
width: width,
height: height,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: shadowColor,
blurRadius: blurRadius,
spreadRadius: spreadRadius,
),
],
),
child: FloatingActionButton(
onPressed: onPressed,
backgroundColor: backgroundColor,
shape: CircleBorder(
side: BorderSide(
color: borderColor,
width: borderWidth,
),
),
child: child,
),
);
}
}
FloatingActionButton を任意の位置に配置する
FloatingActionButton を任意の位置に配置するために、FloatingActionButtonLocation をカスタマイズしたクラスを用意。
BottomNavigationBar への Dock位置と、そこからのオフセットを指定できるようになる。
class CustomizeFloatingLocation extends FloatingActionButtonLocation {
FloatingActionButtonLocation location;
double offsetX;
double offsetY;
CustomizeFloatingLocation(this.location, this.offsetX, this.offsetY);
@override
Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) {
Offset offset = location.getOffset(scaffoldGeometry);
return Offset(offset.dx + offsetX, offset.dy + offsetY);
}
}
BottomNavigationBar
そして、 BottomNavigationBar !
build の部分以外は省略します。
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text('タイトル'),
),
body: const SafeArea(
child: Center(
Text('サンプル',),
),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.photo_outlined),
label: '写真',
),
BottomNavigationBarItem(
icon: Icon(Icons.videocam_outlined),
label: ' ',
),
BottomNavigationBarItem(
icon: Icon(Icons.movie_outlined),
label: '動画',
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
type: BottomNavigationBarType.fixed,
backgroundColor: Theme.of(context).colorScheme.primary,
selectedIconTheme: IconThemeData(size: 30, color: Theme.of(context).colorScheme.secondary),
selectedLabelStyle: TextStyle(color: Theme.of(context).colorScheme.secondary),
selectedItemColor: Theme.of(context).colorScheme.secondary,
unselectedIconTheme: IconThemeData(size: 25, color: Theme.of(context).colorScheme.onPrimary),
unselectedLabelStyle: TextStyle(color: Theme.of(context).colorScheme.onPrimary),
unselectedItemColor: Theme.of(context).colorScheme.onPrimary,
),
floatingActionButtonLocation: CustomizeFloatingLocation(FloatingActionButtonLocation.centerDocked, 0, 28),
floatingActionButton: BlurCircleFloatingActionButton(
onPressed: () async {
},
width: 60,
height: 60,
backgroundColor: Theme.of(context).colorScheme.surface,
borderColor: Theme.of(context).colorScheme.secondary,
borderWidth: 2,
shadowColor: Theme.of(context).colorScheme.secondary.withOpacity(0.5),
blurRadius: 10,
spreadRadius: 5,
child: Icon(Icons.videocam_outlined, color: Theme.of(context).colorScheme.onSurface, size: 36,),
),
);
}
ポイントとしては以下。
- BottomNavigationBarItem は均等に配置するために FAB の裏にも用意してます。
- floatingActionButtonLocation で、バーの中央にドック。
オフセットを指定して下方向にずらしています。
最後に
ちょっとはカッコいい感じにできました!
色々調べると、BottomNavigationBar より BottomAppBar を使った方が、FABの周りに隙間を簡単に作ったり、色々とカスタマイズしやすいらしいです(コードは多めに書く必要があるけど)。