my_appbar.dart 12 KB

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