-1

我正在使用 FlutterFormBuilder 包中的签名板来捕获签名(FlutterFormBuilderSignaturePad),将其上传到 firebase 存储,然后将下载 url 返回到应用程序以存储在 firestore 中的文档中。

我面临的问题是上传需要几秒钟才能完成(在连接不良时可能更长)。我正在尝试等待电话,以便我可以将下载网址传递给数据库,但它忽略了我的尝试。

我试过了 :

  • .then()使用and.whenComplete()但 valueTransformer链接我的调用仍然返回一个空白字符串。
  • 将异步添加到“valueTransformer”、“onSaved”和“onChange”方法并等待调用
  • 在上述三个方法之间移动了保存签名的逻辑,以便给 uimage 上传时间
  • onChanges 触发了很多,所以我引入了一个 _processing 标志,因此它没有多次保存图像并导致数据库超时。onChange 在几秒钟后返回了一个 url,但是我不能保证签名是完整的。

所以我的小部件看起来像这样:

  final SignatureController _controller = SignatureController(
    penStrokeWidth: 5,
    penColor: Colors.red,
    exportBackgroundColor: Colors.blue,
  );
  String _signature;
  File _signatureFile;
  bool _processing;

return FormBuilderSignaturePad(
          name: 'signature',
          controller: _controller,
          decoration: InputDecoration(labelText: "signature"),
          initialValue: _signatureFile?.readAsBytesSync(),
          onSaved: (newValue) async {
            //called on save just before valueTransformer
            await processSignature(newValue, context);
          },
          valueTransformer: (value) {
            //called when the form is saved
            return _signature;
          },
          onChanged: (value) {
            //called frequently as the signature changes
            if (_controller.isNotEmpty) {
              if (_controller.value.length > 19) {
                if (!_processing) {
                  processSignature(value, context).then((value) {
                    setState(() {
                      _processing = false;
                    });
                  });
                }
              }
            }
          },
        )

我处理上传和设置状态的未来

Future<void> processSignature(dynamic signature, BuildContext context) async {
    setState(() {
      _processing = true;
    });
    var bytes = await _controller.toPngBytes();

    final documentDirectory = await getApplicationDocumentsDirectory();
    final file =
        File(join(documentDirectory.path, 'signature${database.uid}.png'));

    file.writeAsBytesSync(bytes);

    var url = await storage.uploadImage(
        context: context,
        imageToUpload: file,
        title: "signature${database.uid}.png",
        requestId: database.currentRequest.id);

    setState(() {
      _signature = url.imageUrl;
      _signatureFile = file;
    });
  }

以下更改后的更新

进程签名:

 Future<String> processSignature(
      dynamic signature, BuildContext context) async {
    var bytes = await _controller.toPngBytes();

    final documentDirectory = await getApplicationDocumentsDirectory();
    final file =
        File(join(documentDirectory.path, 'signature${database.uid}.png'));

    file.writeAsBytesSync(bytes);

    var url = await storage.uploadImage(
        context: context,
        imageToUpload: file,
        title: "signature${database.uid}.png",
        requestId: database.currentRequest.id);

    return url.imageUrl;
  }

签名板小部件:

return FormBuilderSignaturePad(
          name: 'signature',
          controller: _controller,
          decoration: InputDecoration(labelText: "signature"),
          initialValue: _signatureFile?.readAsBytesSync(),
          onSaved: (newValue) async {},
          valueTransformer: (value) async {
            final savedUrl = await processSignature(value, context);
            return savedUrl;
          },
          onChanged: (value) {},
        );

我看到“未来”的方法

_formKey[_currentStep].currentState.save();
if (_formKey[_currentStep].currentState.validate()) {
                      //request from the database
                      var request = firestoreDatabase.currentRequest;

                      //this should be the url however its returning as 
                      //"Future<String>"
                      var value = _formKey[_currentStep].currentState.value;


                      request.questions[_currentStep].result =
                          jsonEncode(_formKey[_currentStep].currentState.value);

                      request.questions[_currentStep].completedOn =
                          Timestamp.fromDate(new DateTime.now());

                      firestoreDatabase.updateRequest(request).then((value) {
                        if (_currentStep == _totalSteps - 1) {
                          //pop the screen
                          Navigator.pop(context);
                        } else {
                          setState(() {
                            _currentStep++;
                          });
                        }
4

1 回答 1

0

在同步调用中不可能返回异步结果。Future意味着它在未来某个地方完成。

processSignature从中删除onChanged(为什么每次修改时都发送签名?)并在onSaved. 然后您可以使用 async/await 将签名发送到服务器并等待结果 url。

class _SomeWidgetState extends State<SomeWidget> {
  /// Form key
  final formKey = GlobalKey<FormState>();

  /// Contains signature binary daya
  Uint8List signatureValue;

  @override
  void build(...) {
    return Column(
      children: [
        FormBuilderSignaturePad(
          ...
          onSaved(Uint8List value) async {
            signatureValue = value;
          },
        FlatButton(
          child: Text('Submit'),
          onPressed: () {
            _submit();
          }
        ),
      ],
    );
  }  

  /// Submits form
  Future< void> _submit() async {
    if (formKey.currentState.validate()) {
      formKey.currentState.save(); // calls all `onSaved` for each form widgets
      // So at this point you have initialized `signatureValue`
      try {
        final signatureUrl = await processSignature(signatureValue, context); // save into database
        await doSomethingWithUrl(signatureUrl); // insert into document
      } on SomeExceptionIfRequired catch (e) {
        // Show error if occurred
        ScaffoldMessenger.of(context).showSnackbar(...);
      }
    }
  }
}
于 2020-12-17T22:02:45.180 回答