my_appbar.dart 12 KB

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