flutter从自定义小部件返回多个字段

时间:2019-01-12 09:33:10

标签: dart flutter

我得到了下面的geolocation.dart文件,该文件可以完美地用作独立的小部件:

import 'package:flutter/material.dart';
import 'package:location/location.dart';
import 'package:flutter/services.dart';
import 'package:simple_permissions/simple_permissions.dart';

class LocationField extends StatefulWidget {
  const LocationField({
    this.fieldKey,
    this.onSaved,
  });

  final Key fieldKey;
  final FormFieldSetter<String> onSaved;

  @override
  _LocationFieldState createState() => _LocationFieldState();
}

class _LocationFieldState extends State<LocationField> {
  Location _location = new Location();

  final lat = TextEditingController();
  final lon = TextEditingController();


  // @override
  // void initState() {
  //   super.initState();
  //  lat.addListener(_addLatValue);
  //  lon.addListener(_addLonValue);
  //}

  @override
  Widget build(BuildContext context) {
    return Row(
      textDirection: TextDirection.rtl,
      children: <Widget>[
        FlatButton(
          child: const Icon(Icons.my_location),
          onPressed: () => _getLocation(),
        ),
        Expanded(child: Column(
            textDirection: TextDirection.ltr,
            children: <Widget>[
                TextFormField(
                  controller: lat,
                  decoration: InputDecoration(
                      prefixIcon: Text("Latittude:     ")
                  ),
                ),
                TextFormField(
                    controller: lon,
                    decoration: InputDecoration(
                        prefixIcon: Text("Longitude:   ")
                    ),
                )
            ])

        )
      ],
    );

  }

  _getLocation() async {
    Map<String, double> location;
    var error = null;

    try {
      await SimplePermissions.requestPermission(Permission.AccessFineLocation);
      location = await _location.getLocation();
    } on PlatformException catch (e) {
      if (e.code == 'PERMISSION_DENIED') {
        error = 'Permission denied';
      } else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {
        error =
        'Permission denied - please ask the user to enable it from the app settings';
      }
      location = null;
    }
    print("error $error");

    setState(() {
          lat.text = ('${location["latitude"]}');
          lon.text = ('${location["longitude"]}');
    });
  }
}

并显示以下内容,单击位置图标时,位置坐标将出现在下面,

enter image description here

我还可以将其作为小部件插入我的主应用程序中,例如:

class _SignUpPageState extends State<SignUpPage> {
     @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(),
      body: Form(
          key: _formKey,
          child: Column(
            children: <Widget>[
              LocationField(),
              RaisedButton(
                onPressed: signUp,
                child: Text('Sign up'),
              ),
            ],
          )
      ),
    );
  }

  void signUp() {
  // what to write here to get the geolocation points lat/lon printed?
}

我的问题是:单击signup按钮后如何获取经纬度打印的地理位置点,如何从子小部件中获取2个字段的值?

1 个答案:

答案 0 :(得分:0)

在Flutter中,使用InheritedWidget&co。将状态沿小部件树向下传递非常容易,而向上传递数据实际上涉及一些思考。

类似于您使用的TextEditingController,您可以创建一个保存位置数据的LocationController

class LocationController {
  Location _location = Location();
  get location => _location;
  set location(Location val) {
    _location = val;
    if (onChanged != null) _onChanged(val);
  }

  VoidCallback _onChanged;
}

然后可以将此控制器传递给LocationField,如下所示:

class LocationField extends StatefulWidget {
  LocationField({
    this.fieldKey,
    @required this.controller,
    this.onSaved,
  });

  final Key fieldKey;
  final LocationController controller;
  final FormFieldSetter<String> onSaved;

  @override
  _LocationFieldState createState() => _LocationFieldState();
}

class _LocationFieldState extends State<LocationField> {
  final lat = TextEditingController();
  final lon = TextEditingController();

  @override
  void initState() {
    super.initState();
    widget.controller._onChanged = (location) => setState(() {
      lat.text = ('${location["latitude"]}');
      lon.text = ('${location["longitude"]}');
    });
    lat.addListener(_addLatValue);
    lon.addListener(_addLonValue);
  }

  @override
  Widget build(BuildContext context) { ... }

  _getLocation() async {
    String error;

    try {
      await SimplePermissions.requestPermission(Permission.AccessFineLocation);
      widget.controller.location = await _location.getLocation();
    } on PlatformException catch (e) {
      if (e.code == 'PERMISSION_DENIED') {
        error = 'Permission denied';
      } else if (e.code == 'PERMISSION_DENIED_NEVER_ASK') {
        error =
        'Permission denied - please ask the user to enable it from the app settings';
      }
      location = null;
    }
    print("error $error");
  }
}

然后,在树上的小部件中,您可以访问控制器以检索位置:

class _SignUpPageState extends State<SignUpPage> {
  LocationController controller = LocationController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Form(
        key: _formKey,
        child: Column(
          children: <Widget>[
            LocationField(controller: controller),
            RaisedButton(onPressed: signUp, child: Text('Sign up')),
          ],
        )
      ),
    );
  }

  void signUp() {
    final location = controller.location;
  }
}

另一个好处是,您可以从树中的小部件中设置controller的{​​{1}},location将自动重建以反映该更改。