my_appbar.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364
  1. import 'package:cs_resources/generated/assets.dart';
  2. import 'package:cs_resources/theme/app_colors_theme.dart';
  3. import 'package:cs_resources/theme/theme_config.dart';
  4. import 'package:flutter/cupertino.dart';
  5. import 'package:flutter/material.dart';
  6. import 'package:flutter/services.dart';
  7. import 'package:flutter/widgets.dart';
  8. import 'package:cs_resources/constants/color_constants.dart';
  9. import 'package:router/ext/auto_router_extensions.dart';
  10. import 'my_load_image.dart';
  11. import 'search_app_bar.dart';
  12. class MyAppBar {
  13. ///封装的默认的AppBar,Light默认模式下,黑色图标+黑色文本,Dark模式下,白色图标+白色文本
  14. static AppBar appBar(BuildContext context, String title,
  15. {void Function()? backCallback,
  16. Key? key,
  17. String? backIconPath = Assets.baseLibNavbarBackIcon,
  18. double? backIconWidth = 44,
  19. double? backIconHeight = 44,
  20. String? subTitle,
  21. Color backgroundColor = Colors.transparent,
  22. Color? titleColor,
  23. Color? titleDarkColor,
  24. SystemUiOverlayStyle? systemUiOverlayStyle,
  25. bool showBottomDivider = false,
  26. bool showBackButton = true, //是否展示返回按钮
  27. List<Widget>? actions}) {
  28. // 检查当前主题是亮色还是暗色
  29. final bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
  30. return AppBar(
  31. key: key,
  32. backgroundColor: backgroundColor,
  33. surfaceTintColor: backgroundColor,
  34. systemOverlayStyle: systemUiOverlayStyle ?? ThemeConfig.getSystemUiOverlayStyleByTheme(context),
  35. // 根据 showBackButton 参数决定是否显示返回按钮
  36. leading: showBackButton
  37. ? (backIconPath != null
  38. ? IconButton(
  39. icon: MyAssetImage(
  40. backIconPath,
  41. width: backIconWidth ?? 11,
  42. height: backIconHeight ?? 18,
  43. ),
  44. onPressed: (){
  45. if (backCallback != null) {
  46. backCallback();
  47. } else {
  48. appRouter.maybePop();
  49. }
  50. },
  51. )
  52. : null) // 使用系统默认返回按钮
  53. : const SizedBox.shrink(),
  54. iconTheme: IconThemeData(color: isDarkMode ? Colors.white : Theme.of(context).colorScheme.primary),
  55. centerTitle: true,
  56. title: subTitle == null
  57. ? Text(
  58. title,
  59. style: TextStyle(color: isDarkMode ? titleDarkColor?? Colors.white : titleColor ?? Colors.black, fontSize: 17, fontWeight: FontWeight.w500),
  60. )
  61. : Column(
  62. mainAxisSize: MainAxisSize.max,
  63. mainAxisAlignment: MainAxisAlignment.center,
  64. crossAxisAlignment: CrossAxisAlignment.center,
  65. children: [
  66. Text(
  67. title,
  68. style: TextStyle(color: isDarkMode ? Colors.white : Colors.black, fontSize: 17, fontWeight: FontWeight.w500),
  69. ),
  70. Text(
  71. subTitle,
  72. style: TextStyle(color: isDarkMode ? Colors.white : Colors.black, fontSize: 15, fontWeight: FontWeight.w400),
  73. )
  74. ],
  75. ),
  76. actions: actions,
  77. elevation: 0.0,
  78. bottom: showBottomDivider
  79. ? PreferredSize(
  80. preferredSize: const Size.fromHeight(0.5),
  81. child: Divider(
  82. height: 0.5,
  83. indent: 0.0,
  84. color: context.appColors.dividerDefault,
  85. ))
  86. : null,
  87. );
  88. }
  89. /// 带搜索的AppBar
  90. static AppBar searchAppBar(BuildContext context,
  91. {void Function()? backCallback,
  92. String? value,
  93. String? hintText,
  94. String? backIconPath = Assets.baseLibNavbarBackIcon,
  95. double? backIconWidth = 44,
  96. double? backIconHeight = 44,
  97. Color textColor = Colors.black,
  98. Color backgroundColor = Colors.transparent,
  99. ValueChanged<String>? onSearch,
  100. ValueChanged<String>? onChanged,
  101. SystemUiOverlayStyle? systemUiOverlayStyle,
  102. TextEditingController? controller,
  103. bool showBottomDivider = false,
  104. List<Widget>? actions}) {
  105. // 检查当前主题是亮色还是暗色
  106. final bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
  107. return AppBar(
  108. backgroundColor: backgroundColor,
  109. surfaceTintColor: backgroundColor,
  110. systemOverlayStyle: systemUiOverlayStyle ?? ThemeConfig.getSystemUiOverlayStyleByTheme(context),
  111. // 标题与其他控件的间隔
  112. titleSpacing: 0,
  113. // 如果没有自带的返回按钮,直接使用系统自带的返回图标
  114. leading: backIconPath != null
  115. ? IconButton(
  116. icon: MyAssetImage(
  117. backIconPath,
  118. width: backIconWidth ?? 11,
  119. height: backIconHeight ?? 18,
  120. ),
  121. onPressed: (){
  122. if (backCallback != null) {
  123. backCallback();
  124. } else {
  125. appRouter.maybePop();
  126. }
  127. },
  128. )
  129. : null,
  130. iconTheme: IconThemeData(color: isDarkMode ? Colors.white : Theme.of(context).colorScheme.primary),
  131. centerTitle: true,
  132. title: SearchAppBar(
  133. onSearch: onSearch,
  134. onChanged: onChanged,
  135. value: value,
  136. hintText: hintText,
  137. controller: controller,
  138. ),
  139. actions: actions,
  140. elevation: 0.0,
  141. bottom: showBottomDivider // 根据变量控制 bottom 的显示
  142. ? const PreferredSize(
  143. preferredSize: Size.fromHeight(0.5),
  144. child: Divider(
  145. height: 0.5,
  146. indent: 0.0,
  147. color: ColorConstants.dividerBar,
  148. ))
  149. : null,
  150. );
  151. }
  152. /// 当前App中的自定义TitleBar用于沉浸式处理,不是用在 Scaffold 下面的,直接放在 Column 下面即可
  153. static Widget titleBar(
  154. BuildContext context,
  155. String title, {
  156. void Function()? backCallback,
  157. String? backIconPath = Assets.baseLibNavbarBackIcon,
  158. double? backIconWidth = 44,
  159. double? backIconHeight = 44,
  160. String? subTitle,
  161. Color backgroundColor = Colors.transparent,
  162. bool showBottomDivider = false,
  163. List<Widget>? actions,
  164. }) {
  165. // 计算左侧和右侧固定容器的宽度
  166. double sideWidth = 55;
  167. // 检查当前主题是亮色还是暗色
  168. final bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
  169. return Column(
  170. children: [
  171. Container(
  172. height: kToolbarHeight,
  173. color: backgroundColor,
  174. child: Stack(
  175. children: [
  176. // 返回图标在左侧
  177. Positioned(
  178. left: 0,
  179. top: 0,
  180. bottom: 0,
  181. child: Container(
  182. width: sideWidth,
  183. alignment: Alignment.center,
  184. child: backIconPath != null
  185. ? IconButton(
  186. icon: MyAssetImage(
  187. backIconPath,
  188. width: backIconWidth ?? 11,
  189. height: backIconHeight ?? 18,
  190. ),
  191. onPressed: () {
  192. if (backCallback != null) {
  193. backCallback();
  194. } else {
  195. appRouter.maybePop();
  196. }
  197. },
  198. )
  199. : BackButton(
  200. color: isDarkMode ? Colors.white : Theme.of(context).colorScheme.primary,
  201. onPressed: () {
  202. if (backCallback != null) {
  203. backCallback();
  204. } else {
  205. appRouter.maybePop();
  206. }
  207. },
  208. ),
  209. ),
  210. ),
  211. // 标题在中间
  212. Positioned.fill(
  213. child: Center(
  214. child: ConstrainedBox(
  215. constraints: BoxConstraints(
  216. maxWidth: MediaQuery.of(context).size.width - 2 * sideWidth,
  217. ),
  218. child: subTitle == null
  219. ? Text(
  220. title,
  221. style: TextStyle(color: isDarkMode ? Colors.white : Colors.black, fontSize: 17, fontWeight: FontWeight.w500),
  222. overflow: TextOverflow.ellipsis,
  223. )
  224. : Column(
  225. mainAxisSize: MainAxisSize.min,
  226. mainAxisAlignment: MainAxisAlignment.center,
  227. crossAxisAlignment: CrossAxisAlignment.center,
  228. children: [
  229. Text(
  230. title,
  231. style: TextStyle(color: isDarkMode ? Colors.white : Colors.black, fontSize: 17, fontWeight: FontWeight.w500),
  232. overflow: TextOverflow.ellipsis,
  233. ),
  234. Text(
  235. subTitle,
  236. style: TextStyle(color: isDarkMode ? Colors.white : Colors.black, fontSize: 15, fontWeight: FontWeight.w400),
  237. ),
  238. ],
  239. ),
  240. ),
  241. ),
  242. ),
  243. // 右侧的操作按钮
  244. Positioned(
  245. right: 0,
  246. top: 0,
  247. bottom: 0,
  248. child: Container(
  249. alignment: Alignment.centerRight,
  250. child: Row(
  251. mainAxisSize: MainAxisSize.min,
  252. children: actions ?? [SizedBox(width: sideWidth)],
  253. ),
  254. ),
  255. ),
  256. ],
  257. ),
  258. ),
  259. // 底部的分割线
  260. if (showBottomDivider)
  261. const Divider(
  262. height: 0.5,
  263. color: ColorConstants.dividerBar,
  264. ),
  265. ],
  266. );
  267. }
  268. /// 当前App中的自定义TitleBar用于沉浸式处理,不是用在 Scaffold 下面的,直接放在 Column 下面即可
  269. static Widget searchTitleBar(
  270. BuildContext context, {
  271. void Function()? backCallback,
  272. String? value,
  273. String? hintText,
  274. String? backIconPath = Assets.baseLibNavbarBackIcon,
  275. double? backIconWidth = 44,
  276. double? backIconHeight = 44,
  277. Color backgroundColor = Colors.transparent,
  278. ValueChanged<String>? onSearch,
  279. ValueChanged<String>? onChanged,
  280. TextEditingController? controller,
  281. bool showBottomDivider = false,
  282. List<Widget>? actions,
  283. }) {
  284. // 检查当前主题是亮色还是暗色
  285. final bool isDarkMode = Theme.of(context).brightness == Brightness.dark;
  286. return Column(
  287. children: [
  288. Container(
  289. height: kToolbarHeight,
  290. color: backgroundColor,
  291. child: Row(
  292. crossAxisAlignment: CrossAxisAlignment.center,
  293. children: [
  294. // 返回图标
  295. Container(
  296. width: 55,
  297. alignment: Alignment.center,
  298. child: backIconPath != null
  299. ? IconButton(
  300. icon: MyAssetImage(
  301. backIconPath,
  302. width: backIconWidth ?? 11,
  303. height: backIconHeight ?? 18,
  304. ),
  305. onPressed: () {
  306. if (backCallback != null) {
  307. backCallback();
  308. } else {
  309. appRouter.maybePop();
  310. }
  311. },
  312. )
  313. : BackButton(
  314. color: isDarkMode ? Colors.white : Theme.of(context).colorScheme.primary,
  315. onPressed: () {
  316. if (backCallback != null) {
  317. backCallback();
  318. } else {
  319. appRouter.maybePop();
  320. }
  321. },
  322. ),
  323. ),
  324. // 搜索栏
  325. Expanded(
  326. child: SearchAppBar(
  327. onSearch: onSearch,
  328. onChanged: onChanged,
  329. value: value,
  330. hintText: hintText,
  331. controller: controller,
  332. ),
  333. ),
  334. // 右侧操作按钮
  335. Container(
  336. alignment: Alignment.centerRight,
  337. child: Row(
  338. mainAxisSize: MainAxisSize.min,
  339. children: actions ?? [],
  340. ),
  341. ),
  342. ],
  343. ),
  344. ),
  345. // 底部的分割线
  346. if (showBottomDivider)
  347. const Divider(
  348. height: 0.5,
  349. indent: 0.0,
  350. color: ColorConstants.dividerBar,
  351. ),
  352. ],
  353. );
  354. }
  355. }