1414// limitations under the License.
1515//
1616
17+ import 'dart:math' ;
18+
1719import 'package:arcgis_maps/arcgis_maps.dart' ;
1820import 'package:flutter/material.dart' ;
1921
@@ -29,114 +31,210 @@ class QueryTableStatisticsSample extends StatefulWidget {
2931
3032class _QueryTableStatisticsSampleState extends State <QueryTableStatisticsSample >
3133 with SampleStateSupport {
34+ // Create a controller for the map view.
3235 final _mapViewController = ArcGISMapView .createController ();
33- final _serviceFeatureTable = ServiceFeatureTable .withUri (Uri .parse (
34- 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer/0' ));
35- bool _onlyCitiesInCurrentExtent = true ;
36- bool _onlyCitiesGreaterThan5M = true ;
37- final _statisticDefinitions = List <StatisticDefinition >.empty (growable: true );
38-
39- @override
40- void initState () {
41- super .initState ();
42-
43- for (final type in StatisticType .values) {
44- _statisticDefinitions.add (
45- StatisticDefinition (onFieldName: 'POP' , statisticType: type),
46- );
47- }
48-
49- final map = ArcGISMap .withBasemapStyle (BasemapStyle .arcGISTopographic);
50- final featureLayer = FeatureLayer .withFeatureTable (_serviceFeatureTable);
51- map.operationalLayers.add (featureLayer);
52-
53- _mapViewController.arcGISMap = map;
54- }
36+ // Create a ServiceFeatureTable from a URL.
37+ final _serviceFeatureTable = ServiceFeatureTable .withUri (
38+ Uri .parse (
39+ 'https://sampleserver6.arcgisonline.com/arcgis/rest/services/SampleWorldCities/MapServer/0' ,
40+ ),
41+ );
42+ // A flag for when the map view is ready and controls can be used.
43+ var _ready = false ;
44+ // A flag for whether to limit the query to cities within the current extent.
45+ var _onlyCitiesInCurrentExtent = true ;
46+ // A flag for whether to limit the query to cities with population greater than 5 million.
47+ var _onlyCitiesGreaterThan5M = true ;
48+ // A list of statistic definitions to apply to the query.
49+ final _statisticDefinitions = < StatisticDefinition > [];
50+ // A flag to display the query settings.
51+ var _settingsVisible = false ;
5552
5653 @override
5754 Widget build (BuildContext context) {
5855 return Scaffold (
59- body: Stack (
60- alignment: Alignment .center,
61- children: [
62- ArcGISMapView (
63- controllerProvider: () => _mapViewController,
64- ),
65- Positioned (
66- width: 350 ,
67- height: 180 ,
68- bottom: 60 ,
69- child: DecoratedBox (
70- decoration: BoxDecoration (
71- color: Colors .white.withOpacity (0.8 ),
72- ),
73- child: Column (
74- mainAxisAlignment: MainAxisAlignment .center,
75- children: [
76- SwitchListTile (
77- title: const Text ('Only cities in current extent' ),
78- value: _onlyCitiesInCurrentExtent,
79- onChanged: (value) {
80- setState (() => _onlyCitiesInCurrentExtent = value);
81- },
82- ),
83- SwitchListTile (
84- title: const Text ('Only cities greater than 5M' ),
85- value: _onlyCitiesGreaterThan5M,
86- onChanged: (value) {
87- setState (() => _onlyCitiesGreaterThan5M = value);
88- },
56+ body: SafeArea (
57+ top: false ,
58+ child: Stack (
59+ children: [
60+ Column (
61+ children: [
62+ Expanded (
63+ // Add a map view to the widget tree and set a controller.
64+ child: ArcGISMapView (
65+ controllerProvider: () => _mapViewController,
66+ onMapViewReady: onMapViewReady,
8967 ),
90- TextButton (
91- onPressed: queryStatistics,
92- child: const Text (
93- 'Get statistics' ,
68+ ),
69+ Row (
70+ mainAxisAlignment: MainAxisAlignment .spaceEvenly,
71+ children: [
72+ // A button to show the Settings bottom sheet.
73+ ElevatedButton (
74+ onPressed: () => setState (() => _settingsVisible = true ),
75+ child: const Text ('Settings' ),
9476 ),
95- ),
96- ],
77+ // A button to calculate the statistics.
78+ ElevatedButton (
79+ onPressed: queryStatistics,
80+ child: const Text ('Get statistics' ),
81+ ),
82+ ],
83+ ),
84+ ],
85+ ),
86+ // Display a progress indicator and prevent interaction until state is ready.
87+ Visibility (
88+ visible: ! _ready,
89+ child: SizedBox .expand (
90+ child: Container (
91+ color: Colors .white30,
92+ child: const Center (child: CircularProgressIndicator ()),
93+ ),
9794 ),
9895 ),
99- ) ,
100- ] ,
96+ ] ,
97+ ) ,
10198 ),
99+ bottomSheet: _settingsVisible ? querySettings (context) : null ,
102100 );
103101 }
104102
103+ // The build method for the query options shown in the bottom sheet.
104+ Widget querySettings (BuildContext context) {
105+ return Container (
106+ color: Colors .white,
107+ padding: EdgeInsets .fromLTRB (
108+ 20.0 ,
109+ 0.0 ,
110+ 20.0 ,
111+ max (
112+ 20.0 ,
113+ View .of (context).viewPadding.bottom /
114+ View .of (context).devicePixelRatio,
115+ ),
116+ ),
117+ child: Container (
118+ color: Colors .white,
119+ child: Column (
120+ mainAxisSize: MainAxisSize .min,
121+ children: [
122+ Row (
123+ children: [
124+ Text (
125+ 'Query Settings' ,
126+ style: Theme .of (context).textTheme.titleMedium,
127+ ),
128+ const Spacer (),
129+ IconButton (
130+ icon: const Icon (Icons .close),
131+ onPressed: () => setState (() => _settingsVisible = false ),
132+ ),
133+ ],
134+ ),
135+ Row (
136+ children: [
137+ Checkbox (
138+ value: _onlyCitiesInCurrentExtent,
139+ onChanged: (value) {
140+ setState (() => _onlyCitiesInCurrentExtent = value! );
141+ },
142+ ),
143+ const Text ('Only cities in current extent' ),
144+ ],
145+ ),
146+ Row (
147+ children: [
148+ Checkbox (
149+ value: _onlyCitiesGreaterThan5M,
150+ onChanged: (value) {
151+ setState (() => _onlyCitiesGreaterThan5M = value! );
152+ },
153+ ),
154+ const Text ('Only cities greater than 5M' ),
155+ ],
156+ ),
157+ ],
158+ ),
159+ ),
160+ );
161+ }
162+
163+ // Called when the map view is ready.
164+ void onMapViewReady () {
165+ // Add the statistic definitions for the 'POP' (Population) field.
166+ for (final type in StatisticType .values) {
167+ _statisticDefinitions.add (
168+ StatisticDefinition (
169+ onFieldName: 'POP' ,
170+ statisticType: type,
171+ ),
172+ );
173+ }
174+ // Create a map with a topographic basemap.
175+ final map = ArcGISMap .withBasemapStyle (
176+ BasemapStyle .arcGISTopographic,
177+ );
178+ // Create a feature layer from the service feature table.
179+ final featureLayer = FeatureLayer .withFeatureTable (
180+ _serviceFeatureTable,
181+ );
182+ // Add the feature layer to the map.
183+ map.operationalLayers.add (
184+ featureLayer,
185+ );
186+ // Set the map to the map view.
187+ _mapViewController.arcGISMap = map;
188+ setState (() => _ready = true );
189+ }
190+
191+ // Query statistics from the service feature table.
105192 void queryStatistics () async {
106- final statisticsQueryParameters =
107- StatisticsQueryParameters (statisticDefinitions: _statisticDefinitions);
193+ // Create a statistics query parameters object.
194+ final statisticsQueryParameters = StatisticsQueryParameters (
195+ statisticDefinitions: _statisticDefinitions,
196+ );
108197
198+ // Set the geometry and spatial relationship if the flag is true.
109199 if (_onlyCitiesInCurrentExtent) {
110200 statisticsQueryParameters.geometry = _mapViewController.visibleArea;
111-
112201 statisticsQueryParameters.spatialRelationship =
113202 SpatialRelationship .intersects;
114203 }
115-
204+ // Set the where clause if the flag is true.
116205 if (_onlyCitiesGreaterThan5M) {
117206 statisticsQueryParameters.whereClause = 'POP_RANK = 1' ;
118207 }
119-
208+ // Query the statistics.
120209 final statisticsQueryResult = await _serviceFeatureTable.queryStatistics (
121- statisticsQueryParameters: statisticsQueryParameters);
122-
123- final statistics = StringBuffer ();
210+ statisticsQueryParameters: statisticsQueryParameters,
211+ );
124212
213+ // Prepare the statistics results for display.
214+ final statistics = [];
125215 final records = statisticsQueryResult.statisticRecords ();
126216 for (final record in records) {
127217 record.statistics.forEach ((key, value) {
128- statistics.write ('\n $key : $value ' );
218+ final displayName =
219+ key.toLowerCase () == 'count_pop' ? 'CITY_COUNT' : key;
220+ final displayValue = key.toLowerCase () == 'count_pop'
221+ ? value.toStringAsFixed (0 )
222+ : value.toStringAsFixed (2 );
223+ statistics.add ('[$displayName ] $displayValue ' );
129224 });
130225 }
131-
226+ // Display the statistics in a dialog.
132227 if (mounted) {
133228 showDialog (
134229 context: context,
135- builder: (BuildContext context) {
230+ builder: (context) {
136231 return AlertDialog (
137- title: const Text ('Statistical Query Results' ),
232+ title: Text (
233+ 'Statistical Query Results' ,
234+ style: Theme .of (context).textTheme.titleMedium,
235+ ),
138236 content: Text (
139- statistics.toString (),
237+ statistics.join ( ' \n ' ). toString (),
140238 ),
141239 );
142240 },
0 commit comments