Flutter-左侧导航栏跟随窗口的宽变化
前言
现在有一个需求:左侧导航栏跟随窗口的宽度变化而变化
- 当宽度>1000时,左侧导航栏全部展示,
- 1000>宽度>500时,左侧导航栏只展示图标,
- 500>宽度时,左侧导航栏消失,顶部出现菜单选择图标,点击后可以选择菜单内容
我们要实现上面的功能就需要使用到屏幕的自适应功能,我这里主要用到的就是LayoutBuilder这个组件
操作流程
- 获取屏幕的宽度
- 当屏幕小于指定值时,左侧导航栏展示一个宽高都为0的组件,反之展示全部内容
- 我的左侧导航栏中的每一项格式相同,因此我将之抽离了出来并命名为LeftNavigationBarItemWidget。当宽度小于一定范围时,LeftNavigationBarItemWidget只展示图标,反之展示图标和文本
- 通过上面的3步就实现了左侧导航栏的变化
具体步骤
1.在左侧导航栏的代码中获取屏幕的宽度
Size screenSize = MediaQuery.of(context).size;
double winWidth = screenSize.width;
2.使用LayoutBuilder组件判断当窗口屏幕小于指定值是展示空内容,反之展示
LayoutBuilder(
builder: (p0, p1) {
if (winWidth < leftNavigationBarSelfValue1) {
return Container();
} else {
return Container(
height: double.infinity,
width: winWidth < leftNavigationBarSelfValue ? 60 : 280,
color: Colors.white,
padding: const EdgeInsets.only(top: 20),
child: SingleChildScrollView(
child: Column(
children: MenuValue.LeftNavigationBarItems.map(
(e) => LeftNavigationBarItemWidget(
item: e,
active: widget.selectRoute == e.route,
)).toList(),
),
),
);
}
},
);
3.当窗口小于一定值后左侧导航栏的每一项(LeftNavigationBarItemWidget组件),就只展示图标,不展示文本内容
LayoutBuilder(
builder: (p0, p1) {
if (winWidth < leftNavigationBarSelfValue) {
return Center(
child: Icon(
Icons.wallet,
color: active ? activeTextColor : initIconColor,
),
);
} else {
return OriginalSizeItemWidget(
active: active,
activeTextColor: activeTextColor,
initIconColor: initIconColor,
widget: widget,
initTextColor: initTextColor);
}
},
)
至此就实现了左侧导航栏跟随窗口宽度改变而改变
全部代码
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:my_app/common/store/limits_of_authority.dart';
import 'package:my_app/common/value/menu.dart';
import 'package:my_app/common/value/self_adaption_value.dart';
import 'package:provider/provider.dart';
import '../../../routes/names.dart';
class LeftNavigationBar extends StatefulWidget {
const LeftNavigationBar({
super.key,
required this.selectRoute,
});
final String selectRoute;
@override
State<LeftNavigationBar> createState() => _LeftNavigationBarState();
}
class _LeftNavigationBarState extends State<LeftNavigationBar> {
@override
Widget build(BuildContext context) {
Size screenSize = MediaQuery.of(context).size;
double winWidth = screenSize.width;
return LayoutBuilder(
builder: (p0, p1) {
if (winWidth < leftNavigationBarSelfValue1) {
return Container();
} else {
return Container(
height: double.infinity,
width: winWidth < leftNavigationBarSelfValue ? 60 : 280,
color: Colors.white,
padding: const EdgeInsets.only(top: 20),
child: SingleChildScrollView(
child: Column(
children: MenuValue.LeftNavigationBarItems.map(
(e) => LeftNavigationBarItemWidget(
item: e,
active: widget.selectRoute == e.route,
)).toList(),
),
),
);
}
},
);
}
}
class LeftNavigationBarItemWidget extends StatefulWidget {
const LeftNavigationBarItemWidget({
super.key,
required this.active,
required this.item,
this.isHeard = false,
});
final bool active;
final LeftNavigationBarItem item;
final bool? isHeard;
@override
State<LeftNavigationBarItemWidget> createState() =>
_LeftNavigationBarItemWidgetState();
}
class _LeftNavigationBarItemWidgetState
extends State<LeftNavigationBarItemWidget> {
bool _hovering = false;
final Color initBgcColor = Colors.white;
final Color activeBgcColor = const Color.fromRGBO(229, 240, 255, 1);
final Color initTextColor = const Color.fromRGBO(40, 40, 40, 1);
final Color activeTextColor = const Color.fromRGBO(0, 111, 255, 1);
final Color initIconColor = const Color.fromRGBO(167, 185, 210, 1);
@override
Widget build(BuildContext context) {
bool active = widget.active || _hovering;
Size screenSize = MediaQuery.of(context).size;
double winWidth = screenSize.width;
return Container(
width: double.infinity,
height: 60,
color: active ? activeBgcColor : initBgcColor,
// padding: ,
child: InkWell(
onTap: () {
Provider.of<LimitsOfAuthorityStore>(context, listen: false)
.selectMenuNum = widget.item.id;
Get.offNamed("/${widget.item.route}");
},
onHover: (value) {
setState(() {
_hovering = value;
});
},
child: !widget.isHeard!
? LayoutBuilder(
builder: (p0, p1) {
if (winWidth < leftNavigationBarSelfValue) {
return Center(
child: Icon(
Icons.wallet,
color: active ? activeTextColor : initIconColor,
),
);
} else {
return OriginalSizeItemWidget(
active: active,
activeTextColor: activeTextColor,
initIconColor: initIconColor,
widget: widget,
initTextColor: initTextColor);
}
},
)
: OriginalSizeItemWidget(
active: active,
activeTextColor: activeTextColor,
initIconColor: initIconColor,
widget: widget,
initTextColor: initTextColor),
),
);
}
}
class OriginalSizeItemWidget extends StatelessWidget {
const OriginalSizeItemWidget({
super.key,
required this.active,
required this.activeTextColor,
required this.initIconColor,
required this.widget,
required this.initTextColor,
});
final bool active;
final Color activeTextColor;
final Color initIconColor;
final LeftNavigationBarItemWidget widget;
final Color initTextColor;
@override
Widget build(BuildContext context) {
return Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 32,
),
Icon(
Icons.wallet,
color: active ? activeTextColor : initIconColor,
),
const SizedBox(
width: 8,
),
Text(
widget.item.label,
style: TextStyle(
color: active ? activeTextColor : initTextColor,
),
),
],
);
}
}
class LeftNavigationBarItem {
//菜单栏对应的Id
final int id;
//菜单栏的图标
final IconData icon;
//菜单栏的文字
final String label;
final String route;
const LeftNavigationBarItem({
required this.icon,
required this.label,
required this.id,
required this.route,
});
}