как вызвать переменную, объявленную в асинхронной функции, в виджет в flutter?

#flutter #async-await

Вопрос:

Здесь я пытаюсь получить доступ к камере из приложения, используя пакет камеры, и я новичок в флаттере. Надеюсь, вы поможете мне в этом

Я создал асинхронный метод и объявил в нем переменную, теперь я хочу вызвать объявленный внутри виджета и попытался вызвать его, но там написано «Неопределенное имя»firstCamera»». Я упомянул https://flutter.dev/docs/cookbook/plugins/picture-using-camera. Но я использовал код на другой странице

Заранее спасибо.

это мой код

 import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:async';
import 'package:camera/camera.dart';

class PrivacyPolicyPage extends StatefulWidget {

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

class _PrivacyPolicyPageState extends State<PrivacyPolicyPage> {


  Future<void> camera() async {

    final cameras = await availableCameras();
    firstCamera = cameras.first;
  }
  CameraDescription? firstCamera;

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: TakePictureScreen(camera:firstCamera,),
    );
  }
}

class TakePictureScreen extends StatefulWidget {


  const TakePictureScreen({Key? key,required this.camera}) : super(key: key);
  final CameraDescription camera;

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

class _TakePictureScreenState extends State<TakePictureScreen> {
  late CameraController _controller;
  late Future<void> _initializeControllerFuture;

  @override
  void initState() {
    super.initState();
    // To display the current output from the Camera,
    // create a CameraController.
    _controller = CameraController(
      // Get a specific camera from the list of available cameras.
      widget.camera,
      // Define the resolution to use.
      ResolutionPreset.medium,
    );

    // Next, initialize the controller. This returns a Future.
    _initializeControllerFuture = _controller.initialize();
    @override
    void dispose() {
      // Dispose of the controller when the widget is disposed.
      _controller.dispose();
      super.dispose();
    }

  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: FutureBuilder<void>(
        future: _initializeControllerFuture,
        builder: (context,snapshot){
          if(snapshot.connectionState == ConnectionState.done){
            //If the Future is complete, display the preview.
            return CameraPreview(_controller);

          }
          else{
          //Other wise,display a loading indicator
            return const Center(child:CircularProgressIndicator());
          }
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () async {
          try{
            await _initializeControllerFuture;
            final image = await _controller.takePicture();
            await Navigator.of(context).push(
              MaterialPageRoute(
                builder:(context) => DisplayPictureScreen(
                  imagePath:image.path,
                )
              )
            );
          } catch(e){
            //If an error occurs, log the error to the console.
            print(e);
          }

        },
        child: const Icon(Icons.camera),
      ),
    );
  }
}

class DisplayPictureScreen extends StatelessWidget {
  final String imagePath;
  const DisplayPictureScreen({Key? key, required this.imagePath}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title:const Text("Display the Picture")),
      body:Image.file(File(imagePath)),
    );
  }
}
 

Ответ №1:

Согласно документу, вам нужно поместить этот код в main.dart перед runApp() :

 // Ensure that plugin services are initialized so that 
// `availableCameras()`
// can be called before `runApp()`
WidgetsFlutterBinding.ensureInitialized();

// Obtain a list of the available cameras on the device.
final cameras = await availableCameras();

// Get a specific camera from the list of available cameras.
final firstCamera = cameras.first;

runApp(
  PrivacyPolicyPage(camera: camera),
);
 

И после этого вы сможете указать firstCamera виджеты в качестве параметра, и они будут доступны там

 class PrivacyPolicyPage extends StatelessWidget {
    PrivacyPolicyPage(required this.camera);
    final CameraDescription camera;

    @override
    Widget build(BuildContext context) {
    return SafeArea(
        child: TakePictureScreen(camera:camera),
    );
  }
}

class TakePictureScreen extends StatefulWidget {
    const TakePictureScreen({Key? key,required this.camera}) : 
        super(key: key);
    final CameraDescription camera;

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

И вы сможете использовать его в _TakePictureScreenState таких widget.camera

Кроме того, вы можете создать InheritedWidget , а затем сможете использовать camera в более глубоких виджетах

Комментарии:

1. Я пробовал и это, но не знаю, как вызвать переменную на другой странице, потому что мне нужно получить доступ к камере на другой странице.

2. Вам просто нужно передать его через дерево в виджет, где вы должны его использовать

Ответ №2:

Вы должны определить переменную вне метода. Ваш класс _PrivacyPolicyPageState должен выглядеть следующим образом:

 class _PrivacyPolicyPageState extends State<PrivacyPolicyPage> {

  // Define outside
  CameraDescription firstCamera;

  Future<void> camera() async {
    // Obtain a list of the available cameras on the device.
    final cameras = await availableCameras();

    // Get a specific camera from the list of available cameras.
    // Assigne a value to firstCamera variable
    firstCamera = cameras.first;

  }
  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: TakePictureScreen(camera:firstCamera,),
    );
  }
}
 

Комментарии:

1. Я попытался это сделать, но там написано «Ошибка: поле» Первая камера «должно быть инициализировано, потому что его тип «Описание камеры» не допускает значения null». И мы не можем использовать поздно

2. Ты в полной безопасности, мой плохой, попробуй CameraDescription? firstCamera; и обязательно сначала позвони в камеру()

3. Я много искал, но все еще не нашел решения, извините, что снова беспокою вас, но это тоже не работает, в нем говорится: «Ошибка: тип аргумента» Описание камеры? «не может быть присвоен типу параметра «Описание камеры», потому что «Описание камеры?» обнуляется, а «Описание камеры » — нет».

4. Не могли бы вы точно скопировать свой код, пожалуйста?

5. я отредактировал код с изменениями, которые вы мне велели сделать