Skip to content

Commit

Permalink
feat:圆圈圈圈按钮
Browse files Browse the repository at this point in the history
  • Loading branch information
longer96 committed Jul 16, 2021
1 parent 2b7ea0a commit 8090e49
Show file tree
Hide file tree
Showing 6 changed files with 314 additions and 3 deletions.
59 changes: 59 additions & 0 deletions lib/bottom/bottom10/bottom_10_page.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import 'package:flutter/material.dart';
import 'package:project/bottom/bottom10/tabIcon_data.dart';
import 'package:project/widget/my_app_bar.dart';
import 'bottom_app_bar_10.dart';

/// flutter 圈圈
class Bottom10Page extends StatefulWidget {
@override
_Bottom10PageState createState() => _Bottom10PageState();
}

class _Bottom10PageState extends State<Bottom10Page> {
int pageIndex = 0;

/// 图标
final List<TabIconData> iconList = TabIconData.tabIconsList;

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(title: '圆圈圈圈菜单'),
body: Stack(
children: [
content(),
bottomBar(),
],
),
);
}

Widget content() {
return Container(
alignment: Alignment.center,
child: Text(pageIndex.toString(),
style: TextStyle(color: Colors.grey[400], fontSize: 80)),
);
}

Widget bottomBar() {
// final double width = MediaQuery.of(context).size.width;
return Positioned(
left: 0,
right: 0,
bottom: 0,
child: BottomAppBar10(
iconList: iconList,
selectedPosition: 1,
selectedCallback: (position) => onClickBottomBar(position),
),
);
}

void onClickBottomBar(int index) {
if (!mounted) return;

debugPrint('longer 点击了 >>> $index');
setState(() => pageIndex = index);
}
}
204 changes: 204 additions & 0 deletions lib/bottom/bottom10/bottom_app_bar_10.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import 'package:flutter/material.dart';
import 'package:project/bottom/bottom10/tabIcon_data.dart';

class BottomAppBar10 extends StatefulWidget {
const BottomAppBar10({
Key? key,
this.selectedPosition = 0,
required this.selectedCallback,
required this.iconList,
}) : super(key: key);

/// 选中下标
final int selectedPosition;
final Function(int selectedPosition) selectedCallback;
final List<TabIconData> iconList;

@override
_BottomAppBar10State createState() => _BottomAppBar10State();
}

class _BottomAppBar10State extends State<BottomAppBar10>
with TickerProviderStateMixin {
/// BottomNavigationBar高度
double barHeight = 56.0;

/// 指示器高度
double indicatorHeight = 44.0;

// /// 选中图标颜色
// Color selectedIconColor = Colors.blue;
//
// /// 默认图标颜色
// Color normalIconColor = Colors.grey;

/// 选中下标
int selectedPosition = 0;

/// 记录上一次的选中下标
int previousSelectedPosition = 0;

/// 选中图标高度
double selectedIconHeight = 30.0;

/// 默认图标高度
double normalIconHeight = 28.0;

double itemWidth = 0;

late AnimationController controller;
late Animation<double> animation;

// TODO
// final myCurve = Cubic(0.68, 0, 0, 1.6);

@override
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) {
itemWidth =
(context.size!.width - barHeight) / (widget.iconList.length - 1);
setState(() {});
});

/// 设置动画时长
controller = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 300),
);

selectedPosition = widget.selectedPosition;
previousSelectedPosition = widget.selectedPosition;
animation = Tween(
begin: selectedPosition.toDouble(),
end: selectedPosition.toDouble())
.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
}

@override
Widget build(BuildContext context) {
final children = <Widget>[];

/// 背景
final background = Container(
height: barHeight + MediaQuery.of(context).padding.bottom,
clipBehavior: Clip.none,
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: const Offset(0.0, 0.0),
blurRadius: 1.0,
spreadRadius: 0.0),
],
),
);

children.add(background);

if (itemWidth == 0) {
return Stack(clipBehavior: Clip.none, children: children);
}

/// 指示器
children.add(
Positioned(
left: 6.0 + animation.value * itemWidth,
// top: (barHeight - indicatorHeight) / 2,
top: 0,
child: Container(
width: indicatorHeight,
height: indicatorHeight,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.yellow,
),
),
),
);

for (var i = 0; i < widget.iconList.length; i++) {
/// 图标中心点计算
final rect = Rect.fromCenter(
center: Offset(28.0 + (i * itemWidth), indicatorHeight / 2),
width: (i == selectedPosition) ? selectedIconHeight : normalIconHeight,
height: (i == selectedPosition) ? selectedIconHeight : normalIconHeight,
);

final rectBg = Rect.fromCenter(
center: Offset(28.0 + (i * itemWidth), barHeight / 2),
width: itemWidth - 1,
height: barHeight,
);

/// 每个Icon 格子 && title
children.add(
Positioned.fromRect(
rect: rectBg,
child: InkWell(
onTap: () => _selectedPosition(i),
child: Container(
alignment: Alignment.bottomCenter,
color: Colors.blue.shade100,
child: Text(widget.iconList[i].title,
style: TextStyle(fontSize: 12)),
),
),
),
);

/// icon
children.add(
AnimatedPositioned.fromRect(
rect: rect,
duration: const Duration(milliseconds: 300),
child: IgnorePointer(
ignoring: true,
child: Container(
// color: Colors.red.shade100,
child: LayoutBuilder(
builder: (context, constraints) {
return Icon(
widget.iconList[i].iconData,
color: Colors.grey[700],
size: constraints.biggest.width,
);
},
),
),
),
),
);
}

return Stack(clipBehavior: Clip.none, children: children);
}

void _selectedPosition(int position) {
/// 去除重复点击
if (position == selectedPosition) return;

previousSelectedPosition = selectedPosition;
selectedPosition = position;

/// 执行动画
animation = Tween(
begin: previousSelectedPosition.toDouble(),
end: selectedPosition.toDouble())
.animate(CurvedAnimation(parent: controller, curve: Curves.linear));
animation.addListener(() {
if (!mounted) return;
setState(() {});
});
controller.forward(from: 0.0);

widget.selectedCallback(selectedPosition);
}

@override
void dispose() {
controller.dispose();
super.dispose();
}
}
41 changes: 41 additions & 0 deletions lib/bottom/bottom10/tabIcon_data.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';

class TabIconData {
TabIconData({
this.iconData = Icons.add,
this.index = 0,
this.title = '',
});

IconData iconData;
int index;
String title;

static List<TabIconData> tabIconsList = <TabIconData>[
TabIconData(
iconData: Icons.water_damage_outlined,
index: 0,
title: 'Home',
),
TabIconData(
iconData: Icons.wallet_giftcard,
index: 1,
title: 'Circle',
),
TabIconData(
iconData: Icons.add,
index: 2,
title: 'Release',
),
TabIconData(
iconData: Icons.add_alert_outlined,
index: 3,
title: 'Notice',
),
TabIconData(
iconData: Icons.widgets_outlined,
index: 3,
title: 'Center',
),
];
}
2 changes: 1 addition & 1 deletion lib/bottom/bottom7/bottom_7_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class _Bottom7PageState extends State<Bottom7Page> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MyAppBar(title: '圈圈菜单'),
appBar: MyAppBar(title: '圆圈圈菜单'),
body: Stack(
children: [
content(),
Expand Down
3 changes: 2 additions & 1 deletion lib/bottom/bottom7/bottom_app_bar_7.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class _BottomAppBar7State extends State<BottomAppBar7>
void initState() {
super.initState();
WidgetsBinding.instance!.addPostFrameCallback((_) {
itemWidth = (context.size!.width - barHeight) / 3;
itemWidth =
(context.size!.width - barHeight) / (widget.iconList.length - 1);
setState(() {});
});

Expand Down
8 changes: 7 additions & 1 deletion lib/bottom/bottom_bar_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:project/bottom/bottom1/bottom_1_page.dart';
import 'package:project/bottom/bottom10/bottom_10_page.dart';
import 'package:project/bottom/bottom2/bottom_2_page.dart';
import 'package:project/bottom/bottom3/bottom_3_page.dart';
import 'package:project/bottom/bottom4/bottom_4_page.dart';
Expand Down Expand Up @@ -62,7 +63,12 @@ class _ButtomBarPageState extends State<ButtomBarPage> {
const SizedBox(height: 10),
ElevatedButton(
onPressed: () => push(Bottom7Page()),
child: Text('圈圈菜单'),
child: Text('圆圈圈菜单'),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () => push(Bottom10Page()),
child: Text('圆圈圈圈菜单'),
),
const SizedBox(height: 10),
ElevatedButton(
Expand Down

0 comments on commit 8090e49

Please sign in to comment.