my_appbar.dart 12 KB

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