#flutter #dart #bloc
#flutter #dart #блок
Вопрос:
Я использую API youtube и разместил кнопку переключения избранного, чтобы заполнить и очистить значок в зависимости от состояния и сохранить их в ListView на новой странице под названием «избранное». На новой странице все работает нормально, поскольку я вижу, что значок избранного заполнен, но не обновляется / обновляется в режиме реального времени в текущем представлении. Если я переключусь на StatefulWidget, я смогу заставить его работать с помощью setstate, но тогда изменения не будут отражены, если я удалю значки со страницы избранного.
Должно быть, что-то не так в моем подходе, поскольку я должен использовать состояние блока для изменения обоих, но на самом деле застрял здесь. Пожалуйста, не могли бы вы взглянуть на мой код и дать мне несколько мыслей или идей?
Файл блока
class MasterBloc extends Bloc<MasterEvents, MasterState> {
@override
MasterState get initialState => MasterState.initialState();
@override
Stream<MasterState> mapEventToState(MasterEvents event) async* {
if (event is MasterSetTab) {
yield this.state.copyWith(currentTab: event.tab);
} else if (event is MasterAddToHistory) {
yield* _addToHistory(event);
} else if (event is MasterRemoveFromHistory) {
yield* _removeFromHistory(event);
} else if (event is MasterToggleInFavorites) {
yield* _toggleInFavorites(event);
} else if (event is MasterLogout) {
yield this.state.copyWith(history: [], currentTab: 0);
}
}
Stream<MasterState> _addToHistory(MasterAddToHistory event) async* {
final int index = this
.state
.history
.indexWhere((item) => item.videoId == event.youtubeVideo.videoId);
if (index == -1) {
final history = List<YoutubeVideo>.from(this.state.history);
history.add(event.youtubeVideo);
yield this.state.copyWith(history: history);
}
}
Stream<MasterState> _removeFromHistory(MasterRemoveFromHistory event) async* {
final history = List<YoutubeVideo>.from(this.state.history);
history.removeAt(event.index);
yield this.state.copyWith(history: history);
}
Stream<MasterState> _toggleInFavorites(MasterToggleInFavorites event) async* {
final int index = this
.state
.favorites
.indexWhere((item) => item.videoId == event.youtubeVideo.videoId);
if (index == -1) {
final favorites = List<YoutubeVideo>.from(this.state.favorites);
favorites.add(event.youtubeVideo);
event.youtubeVideo.isFavorite = true;
yield this.state.copyWith(favorites: favorites);
} else {
final favorites = List<YoutubeVideo>.from(this.state.favorites);
favorites.removeAt(index);
event.youtubeVideo.isFavorite = false;
yield this.state.copyWith(favorites: favorites);
}
}
}
Состояние блока
class MasterState extends Equatable {
final int currentTab;
final List<YoutubeVideo> history;
final List<YoutubeVideo> favorites;
MasterState(
{@required this.currentTab, @required this.history, this.favorites});
static MasterState initialState() =>
MasterState(currentTab: 0, history: [], favorites: []);
MasterState copyWith(
{int currentTab,
List<YoutubeVideo> history,
List<YoutubeVideo> favorites}) {
return MasterState(
currentTab: currentTab ?? this.currentTab,
history: history ?? this.history,
favorites: favorites ?? this.favorites);
}
@override
List<Object> get props => [currentTab, history, favorites];
}
События блока
import 'package:documentales_app/models/youtube_video.dart';
abstract class MasterEvents {}
class MasterSetTab extends MasterEvents {
final int tab;
MasterSetTab(this.tab);
}
class MasterAddToHistory extends MasterEvents {
final YoutubeVideo youtubeVideo;
MasterAddToHistory(this.youtubeVideo);
}
class MasterRemoveFromHistory extends MasterEvents {
final int index;
MasterRemoveFromHistory(this.index);
}
class MasterToggleInFavorites extends MasterEvents {
final YoutubeVideo youtubeVideo;
MasterToggleInFavorites(this.youtubeVideo);
}
class MasterLogout extends MasterEvents {}
Favorites Tab
class FavsTab extends StatefulWidget {
@override
_FavsTabState createState() => _FavsTabState();
}
class _FavsTabState extends State<FavsTab> {
@override
Widget build(BuildContext context) {
final bloc = BlocProvider.of<MasterBloc>(context);
return BlocBuilder<MasterBloc, MasterState>(
builder: (_, state) {
if (state.favorites.length == 0) {
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SvgPicture.asset('assets/icons/empty.svg',
width: 50, color: Colors.greenAccent),
SizedBox(
height: 5,
),
Text(
'No hay favoritos ..',
style: TextStyle(
color: Colors.greenAccent,
fontWeight: FontWeight.bold,
fontSize: 20),
)
],
),
);
}
return ListView.builder(
itemBuilder: (_, index) {
final YoutubeVideo item = state.favorites[index];
return YoutubeVideoItem(
item: item,
onDismissed: () {
bloc.add(MasterToggleInFavorites(item));
},
);
},
itemCount: state.favorites.length,
);
},
condition: (prevState, newState) =>
prevState.favorites.length != newState.favorites.length,
);
}
}
Домашняя вкладка, на которой вызывается состояние
class HomeTab extends StatefulWidget {
@override
_HomeTabState createState() => _HomeTabState();
}
class _HomeTabState extends State<HomeTab> {
AccountApi _accountApi = AccountApi();
YoutubeApi _youtubeApi = YoutubeApi(apiKey: API_KEY);
List<dynamic> _users = [];
List<PlayList> _playlists = [];
List<YoutubeVideo> _newVideos = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_load();
}
_load() async {
final users = await _accountApi.getUsers(1);
final List<PlayList> playLists =
await _youtubeApi.getPlaylists('UCCMksip5JfLMW4AJGsjTYUA');
final List<YoutubeVideo> newVideos = await _youtubeApi
.getPlaylistVideos('PLFXLg_sVKmuujWVeOmrzsM1NnDFa8uoNk');
setState(() {
_users.addAll(users);
_playlists.addAll(playLists);
_newVideos.addAll(newVideos);
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return ListView(
children: [
_isLoading
? HomeTabShimmer()
: Column(
children: [
TopPlayLists(items: _playlists),
SizedBox(height: 10),
NewVideos(
items: _newVideos,
),
SizedBox(height: 5),
],
)
],
);
}
}
Наконец, кнопка переключения
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
masterBloc.add(MasterToggleInFavorites(item));
},
child: CircleContainer(
child: Icon(
//Icons.playlist_add,
item.isFavorite
? Icons.favorite
: Icons.favorite_border,
color: Colors.white,
),
size: 35,
),
),
Комментарии:
1. вы можете посмотреть этот урок здесь: youtube.com/watch?v=TYNbMnaEnmA
Ответ №1:
Вы можете обновить переключатель внутри a BlocBuilder
— виджет перестраивается при изменении состояния. Если в вашем блоке произошло изменение состояния, которое вы хотели бы наблюдать, вызов чего-то вроде context.read<YourBloc>().doSomething()
должен обновить виджеты внутри BlocBuilder
.
Использование BlocListener — это еще один подход, который вы можете использовать.