Ошибка: не удалось найти правильный поставщик выше этого виджета - PullRequest
0 голосов
/ 22 апреля 2020

Я пытаюсь создать кнопку-вкладку, в которой есть список (стек) на первой странице перехода. Почему-то есть эта ошибка, и я просто не могу понять, почему ... Screenshot with error warning

Это мой домашний файл:

class  Home extends StatelessWidget {

  final AuthService _auth = AuthService();
  @override
  Widget build(BuildContext context) {
    return TabContainerIndexedStack();
}}

Это TabContainerIndexStack ():

class TabContainerIndexedStack extends StatefulWidget {
  TabContainerIndexedStack({Key key}) : super(key: key);

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

class _TabContainerIndexedStackState extends State<TabContainerIndexedStack> {
  int tabIndex = 0;
  List<Widget> listScreens;
  @override
  void initState() {
    super.initState();
    listScreens = [
      Tab1(),
      Tab2(),
      Tab3(),
    ];
  }

//  @override
//  bool get wantKeepAlive =>
//      true; //by default it will be null, change it to true.

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      color: Colors.yellow,
      home: Scaffold(
        body: IndexedStack(index: tabIndex, children: listScreens),
        bottomNavigationBar: BottomNavigationBar(
            currentIndex: tabIndex,
            onTap: (int index) {
              setState(() {
                tabIndex = index;
              });
            },
            items: [
              BottomNavigationBarItem(
                icon: Icon(Icons.home),
                title: Text('Tab1'),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.report_problem),
                title: Text('Tab2'),
              ),
              BottomNavigationBarItem(
                icon: Icon(Icons.settings),
                title: Text('Tab3'),
              ),
            ]),
        backgroundColor: Theme.of(context).primaryColor,
      ),
    );
  }
}

Это моя первая вкладка (другие работают !!!)

class Tab1 extends StatefulWidget {
  @override
  _Tab1State createState() => _Tab1State();
}

class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {
  @override
  void initState() {
    super.initState();
    print('initState Tab1');
  }

  @override
  Widget build(BuildContext context) {
    print('build Tab1');
    return Scaffold(
      appBar: AppBar(
        title: Text('Tab1'),
      ),
      body: AuftraegeList()
    );
  }

  @override
  bool get wantKeepAlive => true;
}

Я думаю, что проблема тут же в "body: AuftraegeList (). .. "выше ..

Вот файл AuftraegeList ():

class AuftraegeList extends StatefulWidget {
  @override
  _AuftraegeListState createState() => _AuftraegeListState();
}

class _AuftraegeListState extends State<AuftraegeList> {
  @override
  Widget build(BuildContext context) {

    final auftraege = Provider.of<List<Auftrag>>(context);

    return ListView.builder(
        itemCount: auftraege.length,
        itemBuilder: (context, index){
      return AuftragTile(auftrag: auftraege[index]);
    },
    );
  }
}

Надеюсь, этого достаточно для решения моей проблемы. Я очень плохо знаком с Флаттером, поэтому было бы неплохо, если бы вы могли сказать, где именно я должен изменить ЧТО. Большое спасибо !!!

РЕДАКТИРОВАТЬ: Вот код моего home.dart, который представляет собой код, который представляет список в моем главном представлении.

class  Home extends StatelessWidget {

  final AuthService _auth = AuthService();
  @override
  Widget build(BuildContext context) {
    return TabContainerIndexedStack();
    /*
    return StreamProvider<List<Auftrag>>.value(
    value: DatabaseService().auftraege,
      child: Scaffold(
        bottomNavigationBar: btmBar(),
     backgroundColor: Colors.blue[50],
      appBar: AppBar(
        title: Text('Home title'),
        backgroundColor: Colors.blue,
        elevation: 0.0,
        actions: <Widget>[
          FlatButton.icon(
            icon: Icon(Icons.person),
            label: Text('logout'),
            onPressed: () async{
              await _auth.signOut();
            },
          )
        ],
      ),
        body: AuftraegeList(),
        ),
    );
    */

  }
}

(его часть, которую я закомментировал)

Спасибо !!

РЕДАКТИРОВАТЬ (2) !!!

Последнее редактирование:

Итак, мой первый класс касаний теперь выглядит следующим образом (я изменил в теле сборки Widget [] на databaseService.auftraege после того, как сначала объявил databaseService).

    class Tab1 extends StatefulWidget {
  @override
  _Tab1State createState() => _Tab1State();
}


class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {

  // Where should I put this line? Whereever I put this, it gives me errors (already imported services/database.dart)
  final DatabaseService databaseService = Provider.of<DatabaseService()>(context);

  @override
  void initState() {
    super.initState();
    print('initState Tab1');
  }

  @override
  Widget build(BuildContext context) {
    print('build Tab1');
    return Scaffold(
      appBar: AppBar(
        title: Text('Tab1'),
      ),
      body: Provider(
        create: (context) => databaseService.auftraege,
        child: AuftraegeList(),
      )
    );
  }


  @override
  bool get wantKeepAlive => true;
}

Может быть, его также полезно показать Вы мои службы / база данных

class DatabaseService{

  final String uid;
  DatabaseService({ this.uid });
  // collection reference
   final CollectionReference auftraegeCollection = Firestore.instance.collection('auftraege');

  Future updateUserData(String title, String info, int price, String user) async{
    return await auftraegeCollection.document(uid).setData({
      'title' : title,
      'info': info,
      'price': price,
      'user': user,
    });
  }


  List<Auftrag> _auftragListFromSnapshot(QuerySnapshot snapshot){
    return snapshot.documents.map((doc){
      return Auftrag(
          title: doc.data['title']?? '',
          info: doc.data['info']?? '',
          price: doc.data['price']?? 0,
          user: doc.data['user']?? '',

      );
    }).toList();
  }


  // get auftraege stream
Stream <List<Auftrag>> get auftraege {
    return auftraegeCollection.snapshots()
    .map(_auftragListFromSnapshot);
}
}

Когда оставляете такой код, выдает ошибку в этой строке:

 final DatabaseService databaseService = Provider.of<DatabaseService()>(context);

в моем классе tab1.dart. В «контекстах» и «ошибка:« только элементы stati c могут быть доступны в инициализаторах »и« ошибка: выражение сравнения не может быть операндом другого выражения сравнения », а также« ошибка: оператор «<'isn» t определено для класса 'T Function (BuildContext, {listen: bool})'. "</p>

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

### EDIT (3) ### (Исключение)

═══════════════════════════════════════════════════════════════════════════════════════════════════════════════ ═════════════════════════════════════════════════ было сгенерировано следующее утверждение при создании _BodyBuilder: зависимостьOnInheritedWidgetOfExactType> () или depenOnInheritedElement () было вызвано до того, как _Tab1State.initState () завершено.

Когда изменяется унаследованный виджет, например, если изменяется значение Theme.of (), его зависимые виджеты перестраиваются. Если ссылка зависимого виджета на унаследованный виджет находится в конструкторе или методе initState (), то перестроенный зависимый виджет не будет отражать изменения в унаследованном виджете.

Обычно ссылки на унаследованные виджеты должны встречаться в виджете методы build (). В качестве альтернативы, инициализация на основе унаследованных виджетов может быть помещена в метод didChangeDependencies, который вызывается после initState и всякий раз, когда после этого изменяются зависимости.

Соответствующий виджет, вызывающий ошибки, был: Scaffold file: /// Users / xxxxxxxxxxxxxxx /AndroidStudioProjects/promi_prototype/lib/screens/home/tab_containter_indexedstack.dart:36:13 Когда было сгенерировано исключение, это был стек:

0 StatefulElement.dependOnInheritedElement. (пакет: flutter / src / widgets / framework.dart: 4467: 9)

1 StatefulElement.dependOnInheritedElement (пакет: flutter / src / widgets / framework.dart: 4510: 6)

2 StatefulElement.inheritFromElement (пакет: flutter / src / widgets / framework.dart: 4458: 12)

3 Element.inheritFromWidgetOfExactType (пакет: flutter / src / widgets / framework.dart: 3556: 14)

4 Provider.of (package: provider / src / provider.dart: 259: 19)

В нем указано, что соответствующий виджет, вызывающий ошибки, был: tab_containter_indexedstack.dart, я уже разместил этот код на самое начало моего поста. Симулятор теперь показывает только синий фон с панелью вкладок внизу. Нет текста на других вкладках (работал раньше) и нет предупреждения об ошибке на вкладке 1. Даже нет заголовков.

Привет !! :)

.

.

.

### EDIT (4) ###

Боже мой xD Извините за то, что не работает .. и СПАСИБО за помощь!

Позвольте мне начать сообщение об ошибке:

Следующее утверждение было выдано при построении Provider >> (dirty, state: flutter: _DelegateWidgetState # eb784): flutter: Пытался использовать Provider с подтипом Listenable / Stream (Stream>). flutter: flutter: Вероятно, это ошибка, поскольку провайдер не будет автоматически обновлять flutter зависимых: при обновлении Stream> Вместо этого рассмотрите возможность изменения Provider для более конкретной реализации flutter:, которая обрабатывает механизм обновления, такой как: flutter: flutter: - flutter ListenableProvider: - flutter ChangeNotifierProvider: - flutter ValueListenableProvider: - StreamProvider Соответствующий виджет, вызывающий ошибки, был: flutter: Provider> > flutter: file: ///Users/xxxxxxxxxxxx/AndroidStudioProjects/promi_prototype/lib/screens/my_tabs/tab1.dart: 33: 13

Таким образом, по-прежнему существует проблема с поставщиком в tab1. дротик. Мое предположение состояло в том, чтобы изменить функцию Provider в AuftragList (), потому что там я использовал «старый» способ, такой как Provider.of> (context), точно так же, как вы упомянули в редактировании 18 часов go.

Это то, что я сделал (закомментировано было раньше):

class AuftraegeList extends StatefulWidget {
  @override
  _AuftraegeListState createState() => _AuftraegeListState();
}

class _AuftraegeListState extends State<AuftraegeList> {

  DatabaseService databaseService ;

  @override
  Widget build(BuildContext context) {

    databaseService = Provider.of<DatabaseService>(context);
   // final auftraege = Provider.of<List<Auftrag>>(context);

    return ListView.builder(
       // itemCount: auftraege.length,
       // itemBuilder: (context, index){
          itemCount: databaseService.length, //RED MARK HERE
          itemBuilder: (context, index){
      return AuftragTile(auftrag: databaseService[index]); //RED MARK HERE
    },
    );
  }
}

Я думал, что теперь все в порядке, но я получаю красные отметки под ".lenght" и под "[index]». Компилятор говорит, что я должен создать геттер в файле helpers / database.dart, который я тогда пробовал. Но безуспешно. Тогда я удалил получатели.

У вас есть идея? Правильно ли менять объект Provider в AuftraegeList (), даже если компилятор сказал, что проблема в tap1.dart?

.

1 Ответ

1 голос
/ 22 апреля 2020

РЕДАКТИРОВАТЬ Поскольку вы не сразу используете значение для поставщика Stream в классе Home, вместо него можно использовать Provider следующим образом;

class  Home extends StatelessWidget {

  final AuthService _auth = AuthService();
  @override
  Widget build(BuildContext context) {
    return Provider(
                  create: (context) => DatabaseServices(), 
                  child: TabContainerIndexedStack()
     );
   },
 }

Тогда, когда вам нужен список, вы должны вызвать провайдера класса Service, а не список

final DatabaseService databaseService = Provider.of<DatabaseService>(context);

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

databaseService.auftraege

Изменить 1

Если у вас есть провайдер в домашнем классе, вам не нужно снова обернуть провайдера вокруг AuftraegeList(). Это то, что вы должны сделать.

class _Tab1State extends State<Tab1> with AutomaticKeepAliveClientMixin<Tab1> {


  final DatabaseService databaseService; 

  @override
  void initState() {
    databaseService = Provider.of<DatabaseService>(context);
    super.initState();
    print('initState Tab1');
  }

  @override
  Widget build(BuildContext context) {
    print('build Tab1');
    return Scaffold(
      appBar: AppBar(
        title: Text('Tab1'),
      ),
      body:
        // The use the list directly in this class where needed like `databaseService.auftraege` 
        child: AuftraegeList(),
      )
    );
  }


  @override
  bool get wantKeepAlive => true;
}

Примечание

  1. В виджете с состоянием BuildContext доступен в методе initState и метод build. Таким образом, вы можете использовать BuildContext из этих методов, если только вы неявно передаете его.
  2. Если вам нужен список в классе AuftragList(), получите экземпляр списка, используя Provider.of<DatabaseService>(context)
  3. Если вам нужно, чтобы список автоматически обновлялся при появлении необходимого элемента, вы можете использовать StreamSubscription для прослушивания нужного потока и добавления в список.
  4. При вызове provider of передайте dataType, а не класс. Это Provider.of<DatabaseService>(context), а не Provider.of<DatabaseService()>(context).

Редактировать 2

Поскольку вы получаете поток для своего списка, используйте steamBuilder, чтобы построить свой пользовательский интерфейс

class AuftraegeList extends StatefulWidget {
  @override
  _AuftraegeListState createState() => _AuftraegeListState();
}

class _AuftraegeListState extends State<AuftraegeList> {

  DatabaseService databaseService ;

  @override
  Widget build(BuildContext context) {

    databaseService = Provider.of<DatabaseService>(context);
   // final auftraege = Provider.of<List<Auftrag>>(context);

    return StreamBuilder<List<Auftrag>>( 
        stream: databaseService.auftraege,
        builder: (context, snapshot) {
             if (snapshot.hasData) {
              return  ListView.builder(
                   itemCount: snapshot.data.length, 
                   itemBuilder: (context, index){
                       return AuftragTile(auftrag: snapshot.data[index]);
                  } 
              );
             }else if(snapshot.hasError){
               return Center(child: Text("An error Errored");
             }
             return Center(child: CircularProgessIndicator();
      },

    );
  }
}

Надежда это работает.

...