Блок шаблонов для скрытия и отображения виджетов
Я пытаюсь получить некоторые данные из Интернета и показать их в списке.
Следующее мое 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
метод вызывается в body
из Scaffold
void fetchStudents() {
bloc?.changeVisibilityOfNoInternetViews(false);
bloc?.changeVisibilityOfProgress(true);
bloc?.isNetworkAvailable("1", "1", "2", "0");
}
Предположим, у пользователя есть Интернет, когда приложение открыто, и я могу видеть circularprogressindicator
и затем список данных виден, но предположим, что в начале, когда приложение открыто, и у пользователя нет Интернета, тогда я показываю текст "Нет сети доступен" и кнопку, чтобы повторить попытку, теперь, если пользователь подключился к Интернету, а затем нажмите кнопку, чтобы повторить попытку. Я сразу вижу список данных через несколько секунд вместо circularprogressindicator
Я не могу понять, почему NoInternetviews
не прячутся и progressindicator
отображается при нажатии кнопки повтора перед отображением списка данных.
Мой поток не обновляется после вызова кнопки повтора. Есть ли какие-то предостережения для StreamBuilder
в StreamBuilder
?
Я пытался изменить StreamBuilder
порядок, упомянутый @ivenxu в ответе, но он все равно не работает. Ниже приведены ссылки на прилагаемый код https://drive.google.com/file/d/15Z8jXw1OpwTB1CxDS8sHz8jKyHhLwJp7/view?usp=sharing https://drive.google.com/open?id=1gIXV20S1o5jYRnno_NADabuIj4w163fF
1 ответ
В слое вида вы можете использовать виджет Visibility() и передавать видимый параметр true или false при загрузке данных из Интернета. давайте подумаем, как изменить видимую переменную из блока. Родитель виджета Visibility() StreamBuilder() для потоковой передачи данных об изменениях. для вашего случая вам нужен PublishSubject внутри вашего блока для потоковой передачи и добавления новых данных, и Observable для потоковой передачи этих данных в вашем виджете.
давайте покажем фрагмент кода, чтобы помочь вам, как вы можете его реализовать
Блок содержит PublishSubject и Observable для потоковой передачи и добавления данных.
//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()
],
),
),
);
});
}
Кажется, причина в том, что CircularProgressIndicator находится в цикле обновления потока студентов. И ученик получает только следующий снимок, когда данные возвращаются из интернет-звонка в случае повторной попытки.
Попробуйте изменить порядок потоковых компоновщиков, попробуйте поместить студенческий потоковый компоновщик в компоновщик прогрессивных потоков.
Widget buildList(StudentsBloc bloc) {
return StreamBuilder(
stream: bloc.showProgress,
builder: (context, snapshot) {
bool showProgressIndicator = snapshot.data ?? false;
if (!showProgressIndicator) {
StreamBuilder(
stream: bloc.students,
builder: (context, AsyncSnapshot<StudentModel> snapshot) {
....
//your original code without progress StreamBuilder
}
}
return Visibility(
child: Center(
child: CircularProgressIndicator(),
),
visible: showProgressIndicator ? true : false,
);
},
);
}