【问题标题】:Conditional Rendering of Widgets Flutter小部件 Flutter 的条件渲染
【发布时间】:2020-04-27 22:25:01
【问题描述】:

您好,我是 Flutter 的新手,并且创建了一个表单构建器应用程序。我使用 Cloud Firestore 作为我的数据库。我遇到的问题是尝试根据条件渲染特定的小部件。我已经构建了表单并像这样设置了对象数据:每个项目都有一个包含问题信息的 Questions 对象列表。我想遍历问题对象并检查问题类型,然后根据该问题类型呈现某个小部件(例如,多项选择、图像上传、简短回答等)。理想情况下,它将显示为每页一个问题,并带有下一个按钮。 我想留在一个页面上,并在用户按下下一步时调用/显示其他小部件/功能。

问题是我无法通过条件语句让小部件呈现和/或重定向。现在,我为每个循环设置了一个简单的循环,其中嵌套了一个 switch 语句,但是由于迭代一直持续到页面永远不会呈现的最后一个对象。我的目标是在按下时添加一个按钮将继续迭代。

我有一个查看项目页面,它设置 GetProject 对象,然后调用必要的类函数以从 firestore 获取数据。

class Questions{
  final String question;
  final String number;
  final String type;
  Questions({this.question, this.number, this.type});
  List<String> answers = new List();
}

class GetProject {
  final String docID;
  final String title;
  GetProject({this.docID, this.title});

  List<Questions> questions = new List();

   //....Class Functions below not relevant

}

这是我目前查看项目页面的内容

import 'package:flutter/material.dart';
import '../../models/project.dart';
import '../../Services/getproject.dart';
import 'textquestion.dart';
import 'multiplechoicequestion.dart';
import 'UserLocationInfo.dart';
import 'shortanswerquestion.dart'; 

class ViewProject extends StatefulWidget {
  final String docIDref;
  final String title;
  ViewProject({this.docIDref, this.title});
  @override
  _ViewProjectState createState() => _ViewProjectState();
}

class _ViewProjectState extends State<ViewProject> {


   @override

  Widget build(BuildContext context) {
  GetProject project = new GetProject(docID: widget.docIDref, title: widget.title);
  project.getdataFromProject();
  project.questions.forEach((e){
    var type = e.type;
    switch(type){
      case 'TextInputItem':
      return new TextQuestionWidget(question: e);
      case 'MultipleChoice':
      return new MultQuestionWidget(question: e);
      case 'ShortAnswer':
      return new ShortAnswerQuestion(question: e); 
      case 'UserLocation':
      return new UserLocationInfo(question: e); 
    }
    return null; 
  });
  //project.printproj();
 return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),

      body: Container(
        child: Card(
                  child: ListTile(
                    title: Text('Print Values to debug console'),
                    subtitle: Text(''),
                    trailing: Icon(Icons.arrow_forward_ios),
                    onTap: () {
                      project.printproj();
                    }
                  ),
            ),

      ),
 );

  }
}

这是一个被调用小部件的示例

import '../../Services/getproject.dart';

class UserLocationInfo extends StatefulWidget {
  final Questions question;
  UserLocationInfo({this.question});
  @override
  _UserLocationInfoState createState() => _UserLocationInfoState();
}

class _UserLocationInfoState extends State<UserLocationInfo> {
  @override
  Widget build(BuildContext context) {
    return Container(

    );
  }
}

【问题讨论】:

    标签: flutter dart android-widget flutter-layout


    【解决方案1】:

    非常有趣的问题!!

    我使用 FutureBuilder 发布了一些代码。当您按下标有“NEXT”的按钮时,会根据随机数显示一个小部件(随机数可能是数据库结果)

    谢谢。

    import 'package:flutter/material.dart';
    import 'dart:math';
    
    void main() {
      runApp(new MyApp());
    }
    
    class MyApp extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return MyAppState();
      }
    }
    
    
    class MyAppState extends State<MyApp> {
      @override
      Future<int> _newRandomNumber() async{
        print("_newRandomNumber");
        return await Random().nextInt(4);
      }
    
      Widget build(BuildContext context) {
        return new MaterialApp(
          home: new Scaffold(
              appBar: AppBar(title: Text("Random Widget")),
              body: Center(child:
              FutureBuilder(
                  initialData: 0,
                  future:_newRandomNumber(),
                  builder: (context, snapshot) {
                    if(snapshot.hasData){
                      return getRandomWidget(snapshot.data);
                    }
                  }
              )
          )),
        );
      }
    
      Widget getRandomWidget(int randomNumber) {
        switch(randomNumber){
          case 0:
            return Column(children: <Widget>[
              Text("TextInputItem",textScaleFactor: 4),
              getNextButton()
            ]);
            break;
          case 1:
            return Column(children: <Widget>[
              Text("MultipleChoice",textScaleFactor: 4),
              getNextButton()
            ]);
            break;
          case 2:
            return Column(children: <Widget>[
              Text("ShortAnswer",textScaleFactor: 4),
              getNextButton()
            ]);
            break;
          case 3:
            return Column(children: <Widget>[
            Text("UserLocation",textScaleFactor: 4),
            getNextButton()
            ]);
            break;
        }
      }
    
    
      Widget getNextButton(){
          return RaisedButton(
              child: Text("NEXT"),
              color: Colors.red,
              onPressed: () {
                setState(() {
                  _newRandomNumber();
                });
    
              }
          );
      }
    }
    
    

    【讨论】:

    • 我从未使用过future builder。这看起来很有希望,我会尝试实现它并让你知道。谢谢!
    • 这是我遇到的问题,我将项目对象设置为包含所有问题。所以我需要在 Future Builder 之前调用 getQuestions。然后我需要在未来构建器的未来数据成员中调用 get 类型。问题是在此之前项目没有初始化。
    • 我不知道这是否有帮助,但通常如果您需要初始设置,您可以使用 FutureBuilder 参数构造函数 'initialData' 或覆盖方法 initState。
    【解决方案2】:

    您的代码中似乎几乎没有问题需要解决,因此这可能不是您想要实现的目标,但它会为您提供从这里开始的一般方向。

    class ViewProject extends StatefulWidget {
      final String docIDref;
      final String title;
    
      ViewProject({this.docIDref, this.title});
    
      @override
      _ViewProjectState createState() => _ViewProjectState();
    }
    
    class _ViewProjectState extends State<ViewProject> {
      GetProject project;
      int _currentPage = 0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          // when there is no questions(still loading), show a progress indicator
          body: project.questions == null
              ? Center(child: CircularProgressIndicator())
              // IndexedStack will hide all children except the "index"th child
              : IndexedStack(
                  index: _currentPage,
                  children: project.questions
                      .map((question) => _question(question))
                      .toList(),
                ),
        );
      }
    
      @override
      void initState() {
        project = GetProject(docID: widget.docIDref, title: widget.title);
        super.initState();
      }
    
      // Call this function when you want to move to the next page
      void goToNextPage() {
        setState(() {
          _currentPage++;
        });
      }
    
      Future<void> _getQuestions() async {
        // you mentioned you use firebase for database, so 
        // you have to wait for the data to be loaded from the network
        await project.getdataFromProject();
        setState(() {});
      }
    
      Widget _question(Questions question) {
        switch (question.type) {
          case 'TextInputItem':
            return TextQuestionWidget(question: e);
          case 'MultipleChoice':
            return MultQuestionWidget(question: e);
          case 'ShortAnswer':
            return ShortAnswerQuestion(question: e);
          case 'UserLocation':
            return UserLocationInfo(question: e);
        }
      }
    }
    
    

    我不确定你想在哪里调用 goToNextPage(),所以你必须决定在哪里调用它。

    【讨论】:

    • 我很喜欢这个例子,我将尝试实现它。感谢您的回复!
    猜你喜欢
    • 2017-09-25
    • 2018-09-30
    • 2020-01-25
    • 2021-02-20
    • 2021-09-05
    • 1970-01-01
    • 1970-01-01
    • 2021-03-26
    • 2022-08-09
    相关资源
    最近更新 更多