首页 > 解决方案 > 用于隐藏和取消隐藏小部件的 Bloc 模式

问题描述

我正在尝试从互联网上获取一些数据并将其显示在一个列表中。

以下是我的bloc代码

class StudentsBloc {
  final _repository = Repository();
  final _students = BehaviorSubject<StudentModel>();

  final BehaviorSubject<bool> _showProgress = BehaviorSubject<bool>();
  final BehaviorSubject<bool> _showNoInternetViews = BehaviorSubject<bool>();

  Observable<StudentModel> get students => _students.stream;
  Observable<bool> get showProgress => _showProgress.stream;
  Observable<bool> get showNoInternetViews => _showNoInternetViews.stream;

  //FetchStudent from my Api
  fetchStudents(String disciplineId, String schoolId, String year_id,
      String lastIndex) async {
    final student = await _repository.fetchStudents(
        disciplineId, schoolId, year_id, lastIndex);
    _students.sink.add(student);
  }

  //Check to see if user has internet or not
  isNetworkAvailable(String disciplineId, String schoolId, String year_id,
      String lastIndex) async {
    checkInternetConnection().then((isAvailable) {
      if (isAvailable) {
        fetchStudents(disciplineId, schoolId, year_id, lastIndex);
      } else {
        _students.sink.addError(NO_NETWORK_AVAILABLE);
      }
    });
  }

  Function(bool) get changeVisibilityOfProgress => _showProgress.sink.add;
  Function(bool) get changeVisibilityOfNoInternetViews =>
      _showNoInternetViews.sink.add;

  dispose() {
    _students.close();
    _showProgress.close();
    _showNoInternetViews.close();
  }
}

以下是我隐藏统一小部件的主要代码

Widget buildList(StudentsBloc bloc) {
    return StreamBuilder(
      stream: bloc.students,
      builder: (context, AsyncSnapshot<StudentModel> snapshot) {
        if (snapshot.hasError) {
          bloc.changeVisibilityOfProgress(false);
          bloc.changeVisibilityOfNoInternetViews(true);

          return StreamBuilder(
            stream: bloc.showNoInternetViews,
            builder: (context, snapshot) {
              bool showNoInternetView = snapshot.hasData ?? false;

              return Visibility(
                child: Center(
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      Text("No Network Available"),
                      RaisedButton(
                        onPressed: () {
                          fetchStudents();
                        },
                        child: Text("Retry"),
                      )
                    ],
                  ),
                ),
                visible: showNoInternetView ? true : false,
              );
            },
          );
        }

        if (snapshot.hasData) {
          bloc.changeVisibilityOfProgress(false);
          bloc.changeVisibilityOfNoInternetViews(false);

          return Refresh(
            year_id: "2",
            schoolId: "1",
            lastIndex: "0",
            disciplineId: "1",
            child: ListView.builder(
              itemBuilder: (context, int index) {
                return buildTile(
                    snapshot.data.toBuilder().data.studentData[index]);
              },
              itemCount: snapshot.data.toBuilder().data.studentData.length,
            ),
          );
        }

        if (!snapshot.hasData) {
          return StreamBuilder(
            builder: (context, snapshot) {
              bool showProgressIndicator = snapshot.data ?? false;

              return Visibility(
                child: Center(
                  child: CircularProgressIndicator(),
                ),
                visible: showProgressIndicator ? true : false,
              );
            },
            stream: bloc.showProgress,
          );
        }
      },
    );
  }

buildList方法bodyScaffold

void fetchStudents() {
    bloc?.changeVisibilityOfNoInternetViews(false);
    bloc?.changeVisibilityOfProgress(true);
    bloc?.isNetworkAvailable("1", "1", "2", "0");
  }

假设用户在打开应用程序时有互联网,然后我能够看到circularprogressindicator,然后数据列表可见,但假设在开始时打开应用程序并且用户没有互联网,然后我显示无网络可用文本和按钮重试,现在如果用户已连接到互联网,然后单击按钮重试,我会在几秒钟后直接看到数据列表,而不是circularprogressindicator。我无法理解为什么NoInternetviews没有隐藏并且progressindicator正在显示在显示数据列表之前单击重试按钮。

我的流在调用重试按钮时没有得到更新。StreamBuilderinside有什么警告StreamBuilder吗?

我尝试更改StreamBuilder@ivenxu 在答案中提到的顺序,但它仍然不起作用。以下是附加代码的链接 https://drive.google.com/file/d/15Z8jXw1OpwTB1CxDS8sHz8jKyHhLwJp7/view?usp=sharing https://drive.google.com/open?id=1gIXV20S1o5jYRnno_NADabuIj4w163fF

标签: dartflutterbloc

解决方案


在视图层中,您可以使用Visibility()小部件并在从 Internet 加载数据时传递可见参数 true 或 false。让我们考虑如何从 bloc 更改可见变量。Visibility()小部件的父级 StreamBuilder()用于流式传输更改数据。对于您的情况,您需要在您的 bloc 中使用PublishSubject来流式传输和添加新数据,并且Observable需要在您的小部件上流式传输这些数据。

让我们展示一个代码片段来帮助您如何实现它

该 bloc 包含PublishSubjectObservable以流式传输和添加数据

  //this Subject allows sending data, error and done events to the listener
  final PublishSubject<bool> _progressStateSubject = new PublishSubject();

  //the listener are streaming on changes
  Observable<bool> get progressStateStream => _progressStateSubject.stream;

  //to change your progress state
  void changeProgressState({bool state}) => _progressStateSubject.sink.add(state);

在这里你可以改变你的进度状态

void callWebService() async {
    //when you call your func to fetch your data change your state to true
    changeProgressState(state: true);
    .
    .
    .
    if(response != null){
      //when your call is done change the state to false
      changeProgressState(state: false);
    }
  }

您的进度小部件是

// Loading Widget
  Widget _buildLoadingWidget(Bloc bloc) {
    return StreamBuilder<bool>(
        stream: bloc.progressStateStream,//streaming on changes
        builder: (context, snapshot) {
          return Visibility(
            visible: snapshot.data ?? false,//calling when data changes
            child: Center(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Text("Loading data from API...",
                      textDirection: TextDirection.ltr),
                  CircularProgressIndicator()
                ],
              ),
            ),
          );
        });
  }

推荐阅读