Showing
4 changed files
with
80 additions
and
52 deletions
| ... | @@ -41,6 +41,7 @@ class Results { | ... | @@ -41,6 +41,7 @@ class Results { |
| 41 | PlusCode? plusCode; | 41 | PlusCode? plusCode; |
| 42 | dynamic rating; | 42 | dynamic rating; |
| 43 | int? userRatingsTotal; | 43 | int? userRatingsTotal; |
| 44 | + bool isSelect = false; | ||
| 44 | 45 | ||
| 45 | Results( | 46 | Results( |
| 46 | {this.geometry, | 47 | {this.geometry, |
| ... | @@ -58,11 +59,11 @@ class Results { | ... | @@ -58,11 +59,11 @@ class Results { |
| 58 | this.openingHours, | 59 | this.openingHours, |
| 59 | this.plusCode, | 60 | this.plusCode, |
| 60 | this.rating, | 61 | this.rating, |
| 61 | - this.userRatingsTotal}); | 62 | + this.userRatingsTotal, |
| 63 | + this.isSelect = false}); | ||
| 62 | 64 | ||
| 63 | Results.fromJson(Map<String, dynamic> json) { | 65 | Results.fromJson(Map<String, dynamic> json) { |
| 64 | - geometry = | 66 | + geometry = json['geometry'] != null ? Geometry.fromJson(json['geometry']) : null; |
| 65 | - json['geometry'] != null ? Geometry.fromJson(json['geometry']) : null; | ||
| 66 | icon = json['icon']; | 67 | icon = json['icon']; |
| 67 | iconBackgroundColor = json['icon_background_color']; | 68 | iconBackgroundColor = json['icon_background_color']; |
| 68 | iconMaskBaseUri = json['icon_mask_base_uri']; | 69 | iconMaskBaseUri = json['icon_mask_base_uri']; |
| ... | @@ -79,11 +80,8 @@ class Results { | ... | @@ -79,11 +80,8 @@ class Results { |
| 79 | types = json['types'].cast<String>(); | 80 | types = json['types'].cast<String>(); |
| 80 | vicinity = json['vicinity']; | 81 | vicinity = json['vicinity']; |
| 81 | businessStatus = json['business_status']; | 82 | businessStatus = json['business_status']; |
| 82 | - openingHours = json['opening_hours'] != null | 83 | + openingHours = json['opening_hours'] != null ? OpeningHours.fromJson(json['opening_hours']) : null; |
| 83 | - ? OpeningHours.fromJson(json['opening_hours']) | 84 | + plusCode = json['plus_code'] != null ? PlusCode.fromJson(json['plus_code']) : null; |
| 84 | - : null; | ||
| 85 | - plusCode = | ||
| 86 | - json['plus_code'] != null ? PlusCode.fromJson(json['plus_code']) : null; | ||
| 87 | rating = json['rating']; | 85 | rating = json['rating']; |
| 88 | userRatingsTotal = json['user_ratings_total']; | 86 | userRatingsTotal = json['user_ratings_total']; |
| 89 | } | 87 | } |
| ... | @@ -125,10 +123,8 @@ class Geometry { | ... | @@ -125,10 +123,8 @@ class Geometry { |
| 125 | Geometry({this.location, this.viewport}); | 123 | Geometry({this.location, this.viewport}); |
| 126 | 124 | ||
| 127 | Geometry.fromJson(Map<String, dynamic> json) { | 125 | Geometry.fromJson(Map<String, dynamic> json) { |
| 128 | - location = | 126 | + location = json['location'] != null ? Location.fromJson(json['location']) : null; |
| 129 | - json['location'] != null ? Location.fromJson(json['location']) : null; | 127 | + viewport = json['viewport'] != null ? Viewport.fromJson(json['viewport']) : null; |
| 130 | - viewport = | ||
| 131 | - json['viewport'] != null ? Viewport.fromJson(json['viewport']) : null; | ||
| 132 | } | 128 | } |
| 133 | 129 | ||
| 134 | Map<String, dynamic> toJson() { | 130 | Map<String, dynamic> toJson() { |
| ... | @@ -169,10 +165,8 @@ class Viewport { | ... | @@ -169,10 +165,8 @@ class Viewport { |
| 169 | Viewport({this.northeast, this.southwest}); | 165 | Viewport({this.northeast, this.southwest}); |
| 170 | 166 | ||
| 171 | Viewport.fromJson(Map<String, dynamic> json) { | 167 | Viewport.fromJson(Map<String, dynamic> json) { |
| 172 | - northeast = | 168 | + northeast = json['northeast'] != null ? Location.fromJson(json['northeast']) : null; |
| 173 | - json['northeast'] != null ? Location.fromJson(json['northeast']) : null; | 169 | + southwest = json['southwest'] != null ? Location.fromJson(json['southwest']) : null; |
| 174 | - southwest = | ||
| 175 | - json['southwest'] != null ? Location.fromJson(json['southwest']) : null; | ||
| 176 | } | 170 | } |
| 177 | 171 | ||
| 178 | Map<String, dynamic> toJson() { | 172 | Map<String, dynamic> toJson() { | ... | ... |
| ... | @@ -22,12 +22,10 @@ class AddressSelectPage extends StatefulWidget { | ... | @@ -22,12 +22,10 @@ class AddressSelectPage extends StatefulWidget { |
| 22 | 22 | ||
| 23 | class AddressSelectPageState extends State<AddressSelectPage> { | 23 | class AddressSelectPageState extends State<AddressSelectPage> { |
| 24 | List<nearby.Results> _list = []; | 24 | List<nearby.Results> _list = []; |
| 25 | - int _index = 0; | ||
| 26 | final ScrollController _controller = ScrollController(); | 25 | final ScrollController _controller = ScrollController(); |
| 27 | - LatLng _center = const LatLng(45.521563, -122.677433); | 26 | + LatLng? _center; |
| 28 | late GoogleMapController mapController; | 27 | late GoogleMapController mapController; |
| 29 | bool isLoading = false; | 28 | bool isLoading = false; |
| 30 | - int _markerIdCounter = 1; | ||
| 31 | Map<MarkerId, Marker> markers = <MarkerId, Marker>{}; | 29 | Map<MarkerId, Marker> markers = <MarkerId, Marker>{}; |
| 32 | late StreamSubscription _locationSubscription; | 30 | late StreamSubscription _locationSubscription; |
| 33 | String radius = "1000"; | 31 | String radius = "1000"; |
| ... | @@ -65,44 +63,38 @@ class AddressSelectPageState extends State<AddressSelectPage> { | ... | @@ -65,44 +63,38 @@ class AddressSelectPageState extends State<AddressSelectPage> { |
| 65 | return; | 63 | return; |
| 66 | } | 64 | } |
| 67 | } | 65 | } |
| 68 | - | 66 | + var currentLocation = await location.getLocation(); |
| 69 | - _locationSubscription = location.onLocationChanged.listen((LocationData currentLocation) { | 67 | + _center = LatLng(currentLocation.latitude!, currentLocation.longitude!); |
| 70 | - _center = LatLng(currentLocation.latitude!, currentLocation.longitude!); | 68 | + getNearbyPlaces(""); |
| 71 | - Log.e("currentLocation.latitude ${currentLocation.latitude}"); | 69 | + _goToCurrentCenter(); |
| 72 | - getNearbyPlaces(""); | ||
| 73 | - }); | ||
| 74 | } | 70 | } |
| 75 | 71 | ||
| 76 | void getNearbyPlaces(String keyword) async { | 72 | void getNearbyPlaces(String keyword) async { |
| 77 | String uri = | 73 | String uri = |
| 78 | - '${'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${_center.latitude},${_center.longitude}&radius=$radius'}&key=$apiKey&keyword=$keyword'; | 74 | + '${'https://maps.googleapis.com/maps/api/place/nearbysearch/json?location=${_center?.latitude},${_center?.longitude}&radius=$radius'}&key=$apiKey&keyword=$keyword'; |
| 75 | + print(uri); | ||
| 79 | var url = Uri.parse(uri); | 76 | var url = Uri.parse(uri); |
| 80 | var response = await http.post(url); | 77 | var response = await http.post(url); |
| 81 | nearbyPlacesResponse = nearby.NearbyPlacesResponse.fromJson(jsonDecode(response.body)); | 78 | nearbyPlacesResponse = nearby.NearbyPlacesResponse.fromJson(jsonDecode(response.body)); |
| 82 | _list = nearbyPlacesResponse.results!; | 79 | _list = nearbyPlacesResponse.results!; |
| 80 | + if (_list.isNotEmpty) { | ||
| 81 | + selectItemLocation(_list[0]); | ||
| 82 | + } | ||
| 83 | setState(() { | 83 | setState(() { |
| 84 | isLoading = false; | 84 | isLoading = false; |
| 85 | }); | 85 | }); |
| 86 | + buildMarkers(); | ||
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | void _onMapCreated(GoogleMapController controller) { | 89 | void _onMapCreated(GoogleMapController controller) { |
| 89 | mapController = controller; | 90 | mapController = controller; |
| 90 | - final String markerIdVal = 'marker_id_$_markerIdCounter'; | ||
| 91 | - _markerIdCounter++; | ||
| 92 | - final MarkerId markerId = MarkerId(markerIdVal); | ||
| 93 | - final Marker marker = Marker( | ||
| 94 | - markerId: markerId, | ||
| 95 | - position: _center, | ||
| 96 | - ); | ||
| 97 | - mapController.moveCamera(CameraUpdate.newLatLng(_center)); | ||
| 98 | - setState(() { | ||
| 99 | - markers[markerId] = marker; | ||
| 100 | - }); | ||
| 101 | getNearbyPlaces(""); | 91 | getNearbyPlaces(""); |
| 102 | } | 92 | } |
| 103 | 93 | ||
| 104 | void _goToCurrentCenter() { | 94 | void _goToCurrentCenter() { |
| 105 | - mapController.animateCamera(CameraUpdate.newLatLng(_center)); | 95 | + if (_center != null) { |
| 96 | + mapController.moveCamera(CameraUpdate.newLatLng(_center!)); | ||
| 97 | + } | ||
| 106 | } | 98 | } |
| 107 | 99 | ||
| 108 | @override | 100 | @override |
| ... | @@ -113,12 +105,12 @@ class AddressSelectPageState extends State<AddressSelectPage> { | ... | @@ -113,12 +105,12 @@ class AddressSelectPageState extends State<AddressSelectPage> { |
| 113 | itemCount: _list.length, | 105 | itemCount: _list.length, |
| 114 | separatorBuilder: (_, index) => const Divider(), | 106 | separatorBuilder: (_, index) => const Divider(), |
| 115 | itemBuilder: (_, index) { | 107 | itemBuilder: (_, index) { |
| 108 | + var item = _list[index]; | ||
| 116 | return _AddressItem( | 109 | return _AddressItem( |
| 117 | - isSelected: _index == index, | 110 | + isSelected: item.isSelect, |
| 118 | - date: _list[index], | 111 | + date: item, |
| 119 | onTap: () { | 112 | onTap: () { |
| 120 | - _index = index; | 113 | + selectItemLocation(item); |
| 121 | - setState(() {}); | ||
| 122 | }, | 114 | }, |
| 123 | ); | 115 | ); |
| 124 | }, | 116 | }, |
| ... | @@ -130,25 +122,21 @@ class AddressSelectPageState extends State<AddressSelectPage> { | ... | @@ -130,25 +122,21 @@ class AddressSelectPageState extends State<AddressSelectPage> { |
| 130 | onPressed: (text) async { | 122 | onPressed: (text) async { |
| 131 | isLoading = true; | 123 | isLoading = true; |
| 132 | _controller.animateTo(0.0, duration: const Duration(milliseconds: 10), curve: Curves.ease); | 124 | _controller.animateTo(0.0, duration: const Duration(milliseconds: 10), curve: Curves.ease); |
| 133 | - _index = 0; | ||
| 134 | // 构造检索参数 | 125 | // 构造检索参数 |
| 135 | getNearbyPlaces(text); | 126 | getNearbyPlaces(text); |
| 136 | }, | 127 | }, |
| 137 | ); | 128 | ); |
| 138 | var map = GoogleMap( | 129 | var map = GoogleMap( |
| 139 | onMapCreated: _onMapCreated, | 130 | onMapCreated: _onMapCreated, |
| 140 | - initialCameraPosition: CameraPosition(target: _center, zoom: 16.0), | 131 | + initialCameraPosition: CameraPosition(target: _center ?? const LatLng(45.521563, -122.677433), zoom: 16.0), |
| 141 | markers: Set<Marker>.of(markers.values), | 132 | markers: Set<Marker>.of(markers.values), |
| 142 | ).expanded(flex: 9); | 133 | ).expanded(flex: 9); |
| 134 | + | ||
| 143 | return Scaffold( | 135 | return Scaffold( |
| 144 | resizeToAvoidBottomInset: false, | 136 | resizeToAvoidBottomInset: false, |
| 145 | appBar: searchBar, | 137 | appBar: searchBar, |
| 146 | body: Column( | 138 | body: Column( |
| 147 | - children: <Widget>[ | 139 | + children: <Widget>[map, listHolder, initButton()], |
| 148 | - map, | ||
| 149 | - listHolder, | ||
| 150 | - initButton(), | ||
| 151 | - ], | ||
| 152 | ).safe(), | 140 | ).safe(), |
| 153 | ); | 141 | ); |
| 154 | } | 142 | } |
| ... | @@ -156,15 +144,58 @@ class AddressSelectPageState extends State<AddressSelectPage> { | ... | @@ -156,15 +144,58 @@ class AddressSelectPageState extends State<AddressSelectPage> { |
| 156 | initButton() { | 144 | initButton() { |
| 157 | return MyButton( | 145 | return MyButton( |
| 158 | onPressed: () { | 146 | onPressed: () { |
| 159 | - if (_list.isEmpty) { | 147 | + var selected = _list.where((element) => element.isSelect); |
| 148 | + if (selected.isEmpty) { | ||
| 160 | Toast.show('未选择地址!'); | 149 | Toast.show('未选择地址!'); |
| 161 | return; | 150 | return; |
| 162 | } | 151 | } |
| 163 | - NavigatorUtils.goBackWithParams(context, _list[_index]); | 152 | + |
| 153 | + NavigatorUtils.goBackWithParams(context, selected.first); | ||
| 164 | }, | 154 | }, |
| 165 | text: '确认选择地址', | 155 | text: '确认选择地址', |
| 166 | ); | 156 | ); |
| 167 | } | 157 | } |
| 158 | + | ||
| 159 | + void buildMarkers() { | ||
| 160 | + markers.clear(); | ||
| 161 | + for (var value in _list) { | ||
| 162 | + final MarkerId markerId = MarkerId(buildMarkerId(value)); | ||
| 163 | + final Marker marker = Marker( | ||
| 164 | + icon: value.isSelect ? BitmapDescriptor.defaultMarker : BitmapDescriptor.defaultMarkerWithHue(BitmapDescriptor.hueBlue), | ||
| 165 | + markerId: markerId, | ||
| 166 | + position: buildMarkerLocation(value), | ||
| 167 | + ); | ||
| 168 | + markers[markerId] = marker; | ||
| 169 | + } | ||
| 170 | + setState(() {}); | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | + String buildMarkerId(nearby.Results value) { | ||
| 174 | + var lat = value.geometry?.location?.lat; | ||
| 175 | + var lng = value.geometry?.location?.lng; | ||
| 176 | + return "$lat-$lng"; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + LatLng buildMarkerLocation(nearby.Results value) { | ||
| 180 | + var lat = value.geometry?.location?.lat; | ||
| 181 | + var lng = value.geometry?.location?.lng; | ||
| 182 | + return LatLng(lat ?? 0, lng ?? 0); | ||
| 183 | + } | ||
| 184 | + | ||
| 185 | + void selectItemLocation(nearby.Results item) { | ||
| 186 | + for (var element in _list) { | ||
| 187 | + element.isSelect = false; | ||
| 188 | + } | ||
| 189 | + item.isSelect = true; | ||
| 190 | + var lat = item.geometry?.location?.lat; | ||
| 191 | + var lng = item.geometry?.location?.lng; | ||
| 192 | + if (lat != null && lng != null) { | ||
| 193 | + _center = LatLng(lat, lng); | ||
| 194 | + } | ||
| 195 | + _goToCurrentCenter(); | ||
| 196 | + setState(() {}); | ||
| 197 | + buildMarkers(); | ||
| 198 | + } | ||
| 168 | } | 199 | } |
| 169 | 200 | ||
| 170 | class _AddressItem extends StatelessWidget { | 201 | class _AddressItem extends StatelessWidget { | ... | ... |
| ... | @@ -125,7 +125,7 @@ dependencies: | ... | @@ -125,7 +125,7 @@ dependencies: |
| 125 | google_fonts: ^3.0.1 | 125 | google_fonts: ^3.0.1 |
| 126 | wakelock: ^0.6.1+2 | 126 | wakelock: ^0.6.1+2 |
| 127 | location: ^4.4.0 | 127 | location: ^4.4.0 |
| 128 | - google_maps_flutter: ^2.1.10 | 128 | + google_maps_flutter: ^2.2.1 |
| 129 | http: ^0.13.5 | 129 | http: ^0.13.5 |
| 130 | 130 | ||
| 131 | dependency_overrides: | 131 | dependency_overrides: | ... | ... |
-
Please register or login to post a comment