【问题标题】:How to detect user location and show address in flutter web如何在 Flutter Web 中检测用户位置并显示地址
【发布时间】:2021-01-17 16:12:00
【问题描述】:

我的 Flutter Web 应用程序的地理定位和地理编码不起作用。我在这个站点的一些答案后编码以检测用户的位置,显示地址并将地址信息传递到下一页。我做了2页。在我的“地理定位”页面上,我制作了 2 个按钮。我想在用户单击第一个按钮时显示用户的地址。当他/她点击第二个按钮时,我想保存地址信息并传递到下一页。我怎么做?如果你知道 Flutter web,请给我一些提示。 这是我的页面之一'locationjs.dart';

    @JS('navigator.geolocation') // navigator.geolocation 
      namespace
    library jslocation; // library name can be whatever you 
    want

    import "package:js/js.dart";

    @JS('getCurrentPosition') // Accessing method 
     getCurrentPosition from       Geolocation API
     external void getCurrentPosition(Function 
     success(GeolocationPosition pos));

    @JS()
    @anonymous
    class GeolocationCoordinates {
    external double get latitude;
    external double get longitude;
    external double get altitude;
    external double get accuracy;
    external double get altitudeAccuracy;
    
    external factory GeolocationCoordinates(
    {double latitude,
     double longitude,
  double altitude,
  double accuracy,
  double altitudeAccuracy,
  });
  }

  @JS()
  @anonymous
  class GeolocationPosition {
  external GeolocationCoordinates get coords;

  external factory 
  GeolocationPosition({GeolocationCoordinates coords});
  }

其次,我对屏幕页面进行了如下编码。在屏幕上,第一个按钮用于获取经纬度并显示用户地址,第二个按钮用于保存信息并进入下一页。我应该写什么来做到这一点?;

   import 'package:flutter/foundation.dart';
   import 'package:practice/models/user.dart';
   import 'package:practice/shared/choice.dart';
   import 'package:practice/shared/locationJs.dart';
   import 'package:flutter/material.dart';
   import 'package:js/js.dart';
   import 'package:geolocator/geolocator.dart';

  class Geolocating extends StatefulWidget {
  @override
  _GeolocatingState createState() => _GeolocatingState();
   }

  class _GeolocatingState extends State<Geolocating> {
 User user = User();
   
  void getCurrentPosition() async {
  Position position = await Geolocator()
    .getCurrentPosition(desiredAccuracy: 
  LocationAccuracy.low);

  print(position);
  }

  @override
  Widget build(BuildContext context) {
   return Scaffold(
     body: Center(
      child: Container(
        child: Column(
          children: [
            RaisedButton(child: Text('GPS coordinates'),
               onPressed: () {
               _getCurrentLocation();//get location and show address
              }),
            RaisedButton(
               child: Text('address confirmed'),
               onPressed: () {//save the info and pass to next page
               userModel.address = 
                _getCurrentLocation.toString();
               Navigator.push(context,
                    MaterialPageRoute(
                        builder: (context) => 
               NextPage(userModel: userModel)));
              }),
             ],
            ),
           ),
          ),
         );
        }
       }

 success(pos) {
  try {
  Text(pos.coords.latitude);
  Text(pos.coords.longitude);
} catch (ex) {
  print("Exception thrown : " + ex.toString());
 }
}

 _getCurrentLocation() {
   if (kIsWeb) {
   getCurrentPosition(allowInterop((pos) => success(pos)));
  }
}

我还上传了带有 2 个按钮的屏幕截图;https://i.stack.imgur.com/gGNyo.jpg

【问题讨论】:

  • 你在 web flutter 上解决了这个问题吗? stackoverflow.com/questions/64411270/…
  • 不,我即将放弃显示谷歌地图和显示用户地址。我正在考虑自动完成地址。你呢,赛瑞斯?你的解决了吗?
  • 不,不幸的是我卡住了:-(

标签: flutter web location


【解决方案1】:

我希望这个解决方案可能会有所帮助 - 我相信它可以改进。我猜下面的图片描述了你想要做什么。

主屏幕如下。

您想按下 2 个按钮之一来显示地址,如下图所示。

最后你想按第二个按钮进入下一页,并显示如下地址:

解决步骤如下:

  1. 使用locatioJS.dart,但对其进行调整,使其可以返回经纬度

  2. 使用 Future 将经度和纬度保存在列表中。

  3. 使用 Map Box API 检索给定纬度和经度的地址(反向地理编码)。

在最后一步中,mapbox-Geocodingmapbox-Search 用于反向地理编码,尽管 Mapbox-Geocoding 似乎运行良好 - 为了完整起见,解决方案中还包含 map-box search 反向地理编码,也许它可能为其他任何人工作。请注意,在编写此解决方案时,GeocoderGeolocator 似乎不适用于 Flutter Web。

我很快就会在这里提供完整的代码。(享受!)

Dependencies

cupertino_icons: ^1.0.0
js: ^0.6.2
mapbox_search: ^2.0.1+1
mapbox_geocoding: ^0.1.3

locatioJS.dart

// Change the line below
external void  getCurrentPosition(success(GeolocationPosition pos));
// To this one 
external void  getCurrentPosition(Future<void> 
success(GeolocationPosition pos));

main.dart

import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'locationJs.dart';
import 'package:js/js.dart';
import 'package:mapbox_search/mapbox_search.dart';
import 'package:mapbox_geocoding/mapbox_geocoding.dart';
import 'package:mapbox_geocoding/model/reverse_geocoding.dart';


void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        // Provide a function to handle named routes. Use this function to
        // identify the named route being pushed, and create the correct
        // Screen.
        onGenerateRoute: (settings) {
          // If you push the PassArguments route
          if (settings.name == PassArgumentsScreen.routeName)  {
            // Cast the arguments to the correct type: ScreenArguments.
            final ScreenArguments args = settings.arguments;

            // Then, extract the required data from the arguments and
            // pass the data to the correct screen.
            return MaterialPageRoute(
              builder: (context) {
                return PassArgumentsScreen(
                  title: args.title,
                  message: args.message,
                );
              },
            );
          }
          // The code only supports PassArgumentsScreen.routeName right now.
          // Other values need to be implemented if we add them. The assertion
          // here will help remind us of that higher up in the call stack, since
          // this assertion would otherwise fire somewhere in the framework.
         assert(false, 'Need to implement ${settings.name}');
         return null;
        },
        title: 'Navigation with Arguments',
        home: HomeScreen(),
      
      
        );
  }
}

class HomeScreen extends StatefulWidget {
@override 
_HomeScreen createState() => new _HomeScreen();
}


class _HomeScreen extends State<HomeScreen> {
 
  // variables for keeoing track of state
  bool loading = false;
  List mylatlong ;  // store lat long here
  String currentAddress = 'Not found';  // for the address
  bool pressGeoON = false;  // for keeping track of button state
  bool cmbscritta = false;  // for keeping track of button state
/////////////////////////////////////////////////////////////////////////////////////
     // this sets up the map box api .//
     // open map box account. Then go to your dashboard and copy the APIKey or Token
    //Set up a test api key before running for maboxsearch package
     String apiKey = "paste your Mapbox API key (Token ) here"; 
    // Map-box geocoding requires the initialisation below
     MapboxGeocoding geocoding = MapboxGeocoding("paste your Mapbox API key (Token ) here");     //////////////////////////////////////////////////////////////////////////////////////////
  // set the information needed the lat long here 
  Future _getUserInfo() async {
        setState(() {
          loading = true;
        });
         // call loc here to initiate and get the lat long
         // loc is defined down in the code : line 109
          loc();
        setState(() {
          loading = false;
        });
        
    }

  // function for succesful collecting the lat long 
  success(pos) async   {
          List mypos;
          try {
          //print(pos.coords.latitude); 
          //print(pos.coords.longitude);
          mypos = [pos.coords.latitude, pos.coords.longitude ];                
          } catch (ex) {
            print("Exception thrown : " + ex.toString());
            //user = await GetUserInfo.getInfo(kola);
          }
        // once the lat long is retrieved set the values and sassign to th my lat logn variable
        setState(() {
            mylatlong =   mypos;
            print(mylatlong);
          });       
 }

// define future for getting the lat long
// loc is called in getUserInfo (line 78) which is in turn called in initState
Future<void> loc()  async {
  //check if web.
   if (kIsWeb) {
    // get the the lat long by calling success.  Note allowInterop 
    // which enables Returns a wrapper around a function f  that can be called from JavaScript using package:js 
    // cross check the definition of getCurrentPosition in locatioJS.dart (line 7)
   getCurrentPosition(allowInterop((pos) => success(pos)));
  
  }
 
}

//Reverse geocoding package for getting city name. Get place/city name from latitude and longitude.
  getCity(double lat, double lng) async {
  
    try {
      ReverseGeocoding reverseModel =
          await geocoding.reverseModel(lat, lng, limit: 7, types: 'region'); //types can be region, district, neighborhood see https://docs.mapbox.com/api/search/#data-types
      print(reverseModel.features[0].placeName);
      return (reverseModel.features[0].placeName);
    } catch (Excepetion) {
      return 'Reverse Geocoding Error';
    }
  }

// this future to get getAddressFromLatLng  to return the city name
Future<void> testkey() async {
  await getAddressFromLatLng(apiKey).catchError(print);
  //await placesSearch(apiKey).catchError(print);
}

// the function icalls geocity and uses it to get city name/address
Future getAddressFromLatLng(String apiKey) async {
  
  // *********** using map box search ********************************//
  // this gives empty string sometimes
  // initialise mapbox search api
  var geoCodingService = ReverseGeoCoding(
    apiKey: apiKey,
    //country: "BR",
    limit: 5,
  );
  // get the lat ling stores in the variable mylatlong (line 72) . My latlong is set by loc (line 119)
  var lat = mylatlong[0];
  var long = mylatlong[1];
  // get the address
  var addresses = await geoCodingService.getAddress(Location(
    lat: lat, //-19.984846,
    lng: long , //-43.946852,
  ));
 print(addresses); // print to view resulta
// ***********map box searxh ends here ********************************//

// *********** using map box geocoding ********************************//
// this calls th geoCity function (line 133) and uses map  geocoding to retrieve 
 var newadr = await getCity(lat, long);
  print('the mapbox geocoding api returns $newadr');
// *********** using map box geocoding ********************************//

// set the address to the value returned by mapbox geocoding 
  setState(() {
             currentAddress = newadr ;
          });
/////////////////////////////////////////

}

@override
  void initState() {

    _getUserInfo();
    super.initState();

  }
  @override
  Widget build(BuildContext context) {
   
    
    return Scaffold(
      appBar: AppBar(
        title: Text('Home Screen'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            // A button that navigates to a named route that. The named route
            // extracts the arguments by itself.
            ElevatedButton(
              child: Text("Go to Page 2"),
              onPressed: () {
                 testkey();
                // When the user taps the button, navigate to a named route
                // and provide the arguments as an optional parameter.
                Navigator.pushNamed(

                  
                  context,
                  PassArgumentsScreen.routeName,
                  arguments: ScreenArguments(
                    'Welcome to page 2 ',
                    'This was retrieved from lat long $mylatlong and your adress is $currentAddress',
                  ),
                );
                //getAddressFromLatLng();
               
              },
            ),
            // A button that navigates to a named route. For this route, extract
            // the arguments in the onGenerateRoute function and pass them
            // to the screen.
            ElevatedButton(
              child: cmbscritta ? Text("Geolocation is $mylatlong , address $currentAddress ") : Text("Display lat long"), //Text("Navigate to a named that accepts arguments"),
              onPressed: () {
                // When the user taps the button, navigate to a named route
                // and provide the arguments as an optional parameter.
                testkey();
                setState(() {
                pressGeoON = !pressGeoON;
                cmbscritta = !cmbscritta;
                
                //getAddressFromLatLng();
              });
              
              },
            ),
          ],
        ),
      ),
    );
  }
}
class PassArgumentsScreen extends StatelessWidget {
  static const routeName = '/passArguments';

  final String title;
  final String message;

  // This Widget accepts the arguments as constructor parameters. It does not
  // extract the arguments from the ModalRoute.
  //
  // The arguments are extracted by the onGenerateRoute function provided to the
  // MaterialApp widget.
  const PassArgumentsScreen({
    Key key,
    @required this.title,
    @required this.message,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(title),
      ),
      body: Center(
        child: Text(message),
      ),
    );
  }
}
// You can pass any object to the arguments parameter. In this example,
// create a class that contains both a customizable title and message.
class ScreenArguments {
  final String title;
  final String message;

  ScreenArguments(this.title, this.message);
}

随意调整它以适应您想要实现的更多目标。

最好的。

【讨论】:

  • 嗨,微笑。它运作良好。谢谢。但一个问题是地址不够详细。能得到更详细的地址吗?例如,我想至少得到区名和城市名,但我只有省名和国家名。
  • 嗨,这一行:` await geocoding.reverseModel(lat, lng, limit: 7, types: 'region'); //类型可以是区域、区、邻里参见docs.mapbox.com/api/search/#data-types ` 可能是相关的。将地区更改为地区,还可以查看链接上的信息:我不知道 mapbox 是否对获取地区信息有任何限制。最佳
  • 谢谢!最后一个问题,如何用韩语而不是英语显示地址?
  • 我不知道下面链接中的讨论是否可以工作stackoverflow.com/questions/55889889/… 或使用翻译包pub.dev/packages/translator。可能有更好的方法来解决这个问题。最佳
  • 非常感谢,微笑。虽然翻译问题仍未解决,但我感谢您的时间和详细的解决方案:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-12-05
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 2021-05-20
相关资源
最近更新 更多