common_point_select_address_page.dart 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. import 'dart:io';
  2. import 'package:flutter/cupertino.dart';
  3. import 'package:flutter/material.dart';
  4. import 'package:flutter/src/widgets/framework.dart';
  5. import 'package:flutter_map/flutter_map.dart';
  6. import 'package:flutter_screenutil/flutter_screenutil.dart';
  7. import 'package:get/get.dart';
  8. import 'package:get/get_core/src/get_main.dart';
  9. import 'package:location/base/base_page.dart';
  10. import 'package:location/resource/assets.gen.dart';
  11. import 'package:location/resource/colors.gen.dart';
  12. import 'package:location/resource/string.gen.dart';
  13. import 'package:location/utils/common_expand.dart';
  14. import 'package:sliding_sheet2/sliding_sheet2.dart';
  15. import '../../../router/app_pages.dart';
  16. import '../../../widget/common_view.dart';
  17. import 'common_point_select_address_controller.dart';
  18. class CommonPointSelectAddressPage
  19. extends BasePage<CommonPointSelectAddressController> {
  20. const CommonPointSelectAddressPage({super.key});
  21. static start() {
  22. Get.toNamed(RoutePath.commonPointSelectAddress);
  23. }
  24. @override
  25. bool immersive() {
  26. return true;
  27. }
  28. @override
  29. Widget buildBody(BuildContext context) {
  30. return PopScope(
  31. canPop: false,
  32. onPopInvokedWithResult: (bool didPop, dynamic result) {
  33. if (didPop) {
  34. return;
  35. }
  36. controller.backClick();
  37. },
  38. child: Stack(
  39. children: [
  40. buildMapView(),
  41. buildHeadBgView(),
  42. buildMapLogoView(),
  43. buildLocationFunView(),
  44. buildSlidingSheetView(),
  45. buildToolbarView(),
  46. ],
  47. ),
  48. );
  49. }
  50. Widget buildLocationFunView() {
  51. return Obx(() {
  52. return Positioned(
  53. right: 12.w,
  54. bottom: 0.48.sh + controller.sheetProgress * 0.48.sh,
  55. child: Opacity(
  56. opacity: 1 - controller.sheetProgress,
  57. child: GestureDetector(
  58. onTap: controller.moveToCurrentLocation,
  59. child: Container(
  60. width: 38.w,
  61. height: 38.w,
  62. decoration: BoxDecoration(
  63. color: ColorName.white,
  64. borderRadius: BorderRadius.circular(10.r),
  65. boxShadow: [
  66. BoxShadow(
  67. color: ColorName.black10,
  68. blurRadius: 16,
  69. spreadRadius: 2,
  70. offset: Offset(0, 4.w),
  71. ),
  72. ],
  73. ),
  74. child: Center(
  75. child: Assets.images.iconCurrentLocation
  76. .image(width: 20.w, height: 20.w),
  77. )),
  78. ),
  79. ),
  80. );
  81. });
  82. }
  83. Widget buildMapLogoView() {
  84. return Visibility(
  85. visible: Platform.isAndroid,
  86. child: Obx(() {
  87. return Positioned(
  88. left: 12.w,
  89. bottom: 0.465.sh + controller.sheetProgress * 0.48.sh,
  90. child: Opacity(
  91. opacity: 1 - controller.sheetProgress,
  92. child: Column(
  93. crossAxisAlignment: CrossAxisAlignment.start,
  94. children: [
  95. Assets.images.iconAmapLogo.image(height: 20.w),
  96. Text(StringName.locationAmapCo,
  97. style: TextStyle(
  98. fontSize: 9.sp, color: '#666666'.color, height: 1))
  99. ],
  100. ),
  101. ));
  102. }),
  103. );
  104. }
  105. Widget buildSlidingSheetView() {
  106. return SlidingSheet(
  107. listener: (SheetState state) {
  108. controller.setSheetProgress(state.progress);
  109. },
  110. controller: controller.sheetController,
  111. color: ColorName.transparent,
  112. elevation: 0,
  113. shadowColor: ColorName.transparent,
  114. cornerRadius: 0,
  115. snapSpec: SnapSpec(
  116. initialSnap: 0.45,
  117. // Enable snapping. This is true by default.
  118. snap: true,
  119. // Set custom snapping points.
  120. snappings: [0.45, 0.94],
  121. // Define to what the snappings relate to. In this case,
  122. // the total available space that the sheet can expand to.
  123. positioning: SnapPositioning.relativeToAvailableSpace,
  124. ),
  125. headerBuilder: selectAddressHeaderBuilder,
  126. customBuilder: selectAddressCustomBuilder);
  127. }
  128. Widget buildToolbarView() {
  129. return SafeArea(
  130. child: Container(
  131. padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 14.5.w),
  132. child: Row(
  133. children: [
  134. GestureDetector(
  135. onTap: controller.backClick,
  136. child: CommonView.getBackBtnView()),
  137. Spacer(),
  138. Container(
  139. width: 50.w,
  140. height: 28.w,
  141. decoration: BoxDecoration(
  142. color: ColorName.white,
  143. borderRadius: BorderRadius.circular(8.r),
  144. ),
  145. child: Center(
  146. child: Text(StringName.selectAddressDone,
  147. style: TextStyle(
  148. fontSize: 12.sp,
  149. color: ColorName.black90,
  150. fontWeight: FontWeight.bold)),
  151. )),
  152. ],
  153. ),
  154. ),
  155. );
  156. }
  157. Widget buildHeadBgView() {
  158. return IgnorePointer(
  159. child: AspectRatio(
  160. aspectRatio: 360 / 146,
  161. child: Assets.images.bgCommonPointSelectAddressTop.image(
  162. width: double.infinity,
  163. ),
  164. ),
  165. );
  166. }
  167. Widget selectAddressCustomBuilder(BuildContext context,
  168. ScrollController scrollController, SheetState state) {
  169. return ListView.builder(
  170. padding: EdgeInsets.zero,
  171. controller: scrollController,
  172. itemBuilder: (ctx, index) => Text('selectAddressCustomBuilder--$index'),
  173. itemCount: 100,
  174. );
  175. }
  176. Widget selectAddressHeaderBuilder(BuildContext context, SheetState state) {
  177. return IntrinsicHeight(
  178. child: Column(
  179. children: [
  180. buildRangeView(),
  181. SizedBox(height: 12.w),
  182. buildSelectAddressView()
  183. ],
  184. ),
  185. );
  186. }
  187. Widget buildSelectAddressView() {
  188. return GestureDetector(
  189. onTap: controller.onOpenSearchAddressModel,
  190. child: Container(
  191. padding: EdgeInsets.all(12.w),
  192. width: double.infinity,
  193. decoration: BoxDecoration(
  194. color: ColorName.white,
  195. borderRadius: BorderRadius.only(
  196. topLeft: Radius.circular(18.r),
  197. topRight: Radius.circular(18.r))),
  198. child: Obx(() {
  199. return Container(
  200. width: double.infinity,
  201. height: 40.w,
  202. decoration: BoxDecoration(
  203. border: controller.sheetProgress == 1
  204. ? Border.all(color: '#EAECEE'.color, width: 0.5.w)
  205. : null,
  206. color: '#F6F6F8'.color,
  207. borderRadius: BorderRadius.circular(8.r)),
  208. child: Row(
  209. children: [
  210. SizedBox(width: 12.w),
  211. Assets.images.iconCommonPointSearch
  212. .image(width: 14.w, height: 14.w),
  213. SizedBox(width: 6.w),
  214. Expanded(
  215. child: TextField(
  216. enabled: controller.sheetProgress == 1,
  217. controller: controller.searchEditController,
  218. focusNode: controller.searchFocusNode,
  219. style: TextStyle(
  220. fontSize: 14.sp, color: ColorName.primaryTextColor),
  221. maxLines: 1,
  222. maxLength: 30,
  223. keyboardType: TextInputType.text,
  224. textAlignVertical: TextAlignVertical.center,
  225. textInputAction: TextInputAction.next,
  226. decoration: InputDecoration(
  227. hintText:
  228. StringName.selectAddressPleaseEnterPlaceName,
  229. counterText: '',
  230. hintStyle: TextStyle(
  231. fontSize: 13.sp, color: ColorName.black40),
  232. contentPadding: const EdgeInsets.all(0),
  233. border: const OutlineInputBorder(
  234. borderSide: BorderSide.none)))),
  235. SizedBox(width: 12.w),
  236. ],
  237. ),
  238. );
  239. }),
  240. ),
  241. );
  242. }
  243. Widget buildRangeView() {
  244. return Obx(() {
  245. return Opacity(
  246. opacity: 1 - controller.sheetProgress,
  247. child: Container(
  248. width: 336.w,
  249. height: 41.w,
  250. decoration: BoxDecoration(
  251. color: ColorName.white,
  252. borderRadius: BorderRadius.circular(12.r)),
  253. child: Builder(builder: (context) {
  254. return Row(
  255. children: [
  256. SizedBox(width: 16.w),
  257. Text(StringName.selectAddressCommonlyUsedRange,
  258. style:
  259. TextStyle(fontSize: 12.sp, color: ColorName.black80)),
  260. SizedBox(width: 8.w),
  261. Expanded(
  262. child: SliderTheme(
  263. data: SliderTheme.of(context).copyWith(
  264. thumbColor: Colors.white,
  265. thumbShape: CustomBlueThumb(
  266. thumbRadius: 4.6.w,
  267. outerRingWidth: 2.5.w,
  268. color: ColorName.colorPrimary,
  269. ),
  270. overlayShape: SliderComponentShape.noOverlay,
  271. trackHeight: 6.w,
  272. activeTrackColor: ColorName.colorPrimary,
  273. inactiveTrackColor: "#E4E4E4".color,
  274. trackShape: CustomTrackShape(),
  275. ),
  276. child: Obx(() {
  277. return Slider(
  278. value: controller.commonPointRange,
  279. min: 50,
  280. max: 500,
  281. onChanged: (value) {
  282. controller.setCommonPointRange(value);
  283. },
  284. onChangeStart: (value) {
  285. controller.setCommonPointRangeStart();
  286. },
  287. onChangeEnd: (value) {
  288. controller.setCommonPointRangeEnd();
  289. },
  290. );
  291. }),
  292. ),
  293. ),
  294. SizedBox(width: 8.w),
  295. Container(
  296. width: 48.w,
  297. height: 21.w,
  298. decoration: BoxDecoration(
  299. color: '#F6F6F8'.color,
  300. borderRadius: BorderRadius.circular(5.w)),
  301. child: Center(child: Obx(() {
  302. return Text(
  303. '${controller.commonPointRange.toInt()}m',
  304. style:
  305. TextStyle(fontSize: 12.sp, color: ColorName.black80),
  306. );
  307. })),
  308. ),
  309. SizedBox(width: 16.w),
  310. ],
  311. );
  312. }),
  313. ),
  314. );
  315. });
  316. }
  317. Widget buildMapView() {
  318. return SizedBox(
  319. width: double.infinity,
  320. height: 0.65.sh,
  321. child: Stack(
  322. children: [
  323. MapWidget(controller: controller.mapController),
  324. Center(
  325. child: Container(
  326. width: 18.w,
  327. height: 18.w,
  328. decoration: BoxDecoration(
  329. shape: BoxShape.circle,
  330. color: ColorName.colorPrimary,
  331. border: Border.all(color: ColorName.white, width: 2.w),
  332. ),
  333. ),
  334. )
  335. ],
  336. ));
  337. }
  338. }
  339. class CustomTrackShape extends RoundedRectSliderTrackShape {
  340. @override
  341. Rect getPreferredRect({
  342. required RenderBox parentBox,
  343. Offset offset = Offset.zero,
  344. required SliderThemeData sliderTheme,
  345. bool isEnabled = false,
  346. bool isDiscrete = false,
  347. }) {
  348. final trackHeight = sliderTheme.trackHeight;
  349. final trackLeft = offset.dx;
  350. final trackTop = offset.dy + (parentBox.size.height - trackHeight!) / 2;
  351. final trackWidth = parentBox.size.width;
  352. return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
  353. }
  354. }
  355. class CustomBlueThumb extends SliderComponentShape {
  356. final double thumbRadius;
  357. final double outerRingWidth;
  358. final Color color;
  359. const CustomBlueThumb({
  360. this.thumbRadius = 12.0,
  361. this.outerRingWidth = 3.0,
  362. this.color = const Color(0xFF4476FF),
  363. });
  364. @override
  365. Size getPreferredSize(bool isEnabled, bool isDiscrete) {
  366. return Size.fromRadius(thumbRadius + outerRingWidth);
  367. }
  368. @override
  369. void paint(
  370. PaintingContext context,
  371. Offset center, {
  372. required Animation<double> activationAnimation,
  373. required Animation<double> enableAnimation,
  374. required bool isDiscrete,
  375. required TextPainter labelPainter,
  376. required RenderBox parentBox,
  377. required SliderThemeData sliderTheme,
  378. required TextDirection textDirection,
  379. required double value,
  380. required double textScaleFactor,
  381. required Size sizeWithOverflow,
  382. }) {
  383. final Canvas canvas = context.canvas;
  384. final Paint outerPaint = Paint()
  385. ..color = color // 使用您指定的蓝色
  386. ..strokeWidth = outerRingWidth
  387. ..style = PaintingStyle.stroke;
  388. final Paint innerPaint = Paint()
  389. ..color = Colors.white
  390. ..style = PaintingStyle.fill;
  391. // 绘制蓝色外圈
  392. canvas.drawCircle(center, thumbRadius + outerRingWidth / 2, outerPaint);
  393. // 绘制白色内圆
  394. canvas.drawCircle(center, thumbRadius, innerPaint);
  395. }
  396. }