my_appbar.dart 12 KB

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