my_appbar.dart 12 KB

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