在 Flutter with Bloc 中切换不可关闭事件中的收藏夹
Toogle Favorites in onDismissable event in Flutter with Bloc
我在完成与我应该如何从列表(来自 api 响应)add/remove(切换)收藏夹相关的操作时遇到了一些问题。实际上,我可以将收藏夹添加到列表中,也可以以单独的方式将其删除,但我不能以切换方式使用相同的按钮来完成。简而言之,它正在工作,但我无法正确实现切换操作。请您看一下代码,看看是否有一种好的方法可以在不使用 setstate 的情况下实现切换?
关闭按钮(从列表中删除)
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
onDismissed();
},
child: CircleContainer(
child: Icon(
item.isFavorite
? Icons.favorite
: Icons.favorite_border,
color: Colors.white,
),
size: 35,
),
),
使用 Bloc 实现将收藏夹添加到列表的相同按钮
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
masterBloc.add(MasterAddToFavorites(item));
},
child: CircleContainer(
child: Icon(
item.isFavorite
? Icons.favorite
: Icons.favorite_border,
color: Colors.white,
),
size: 35,
),
),
项目定义
class YoutbeVideo {
final String videoId, title, description, banner;
bool isFavorite;
YoutbeVideo(
{@required this.videoId,
@required this.title,
@required this.description,
@required this.banner,
this.isFavorite});
void toggleFavoriteStatus() {
isFavorite = !isFavorite;
}
BloC 代码分为 3 个文件
master_bloc
import 'package:bloc/bloc.dart';
import 'package:documentales_app/models/youtube_video.dart';
import 'master_events.dart';
import 'master_state.dart';
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 MasterRemoveFromFavorites) {
yield* _removeFromFavorites(event);
} else if (event is MasterLogout) {
yield this.state.copyWith(history: [], currentTab: 0);
} else if (event is MasterAddToFavorites) {
yield* _addToFavorites(event);
}
}
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> _addToFavorites(MasterAddToFavorites 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);
yield this.state.copyWith(favorites: favorites);
}
}
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> _removeFromFavorites(
MasterRemoveFromFavorites event) async* {
final favorites = List<YoutubeVideo>.from(this.state.favorites);
favorites.removeAt(event.index);
yield this.state.copyWith(favorites: favorites);
}
}
主状态
import 'package:meta/meta.dart' show required;
import 'package:documentales_app/models/youtube_video.dart';
import 'package:equatable/equatable.dart';
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 MasterAddToFavorites extends MasterEvents {
final YoutubeVideo youtubeVideo;
MasterAddToFavorites(this.youtubeVideo);
}
class MasterRemoveFromHistory extends MasterEvents {
final int index;
MasterRemoveFromHistory(this.index);
}
class MasterRemoveFromFavorites extends MasterEvents {
final int index;
MasterRemoveFromFavorites(this.index);
}
因此执行切换的一种方法是仅用一个替换添加和删除事件。所以你可以摆脱这些事件:
class MasterAddToFavorites extends MasterEvents {
final YoutubeVideo youtubeVideo;
MasterAddToFavorites(this.youtubeVideo);
}
class MasterRemoveFromFavorites extends MasterEvents {
final int index;
MasterRemoveFromFavorites(this.index);
}
并将其替换为:
class MasterToggleInFavorites extends MasterEvents {
final YoutubeVideo video;
MasterToggleInFavorites(video);
}
接下来,在 bloc 内部,在处理该事件的方法内部,您可以这样做:
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.isFavourite = true;
yield this.state.copyWith(favorites: favorites);
} else {
final favorites = List<YoutubeVideo>.from(this.state.favorites);
favorites.removeAt(index);
event.youtubeVideo.isFavourite = false;
yield this.state.copyWith(favorites: favorites);
}
视频Class
class YoutubeVideo {
final String videoId, title, description, banner;
bool isFavorite;
YoutubeVideo(
{@required this.videoId,
@required this.title,
@required this.description,
@required this.banner,
this.isFavorite = false});
factory YoutubeVideo.fromJson(Map<String, dynamic> json,
{bool fromPlayList = false}) {
final snippet = json['snippet'];
final thumbnail =
snippet['thumbnails']['standard'] ?? snippet['thumbnails']['high'];
String videoId;
if (!fromPlayList) {
videoId = json['contentDetails']['videoId'];
} else {
videoId = snippet['resourceId']['videoId'];
}
return YoutubeVideo(
videoId: videoId,
title: snippet['title'],
description: snippet['description'],
banner: thumbnail['url']);
}
}
这里是 onPressed 动作,但出于任何原因没有反映颜色变化
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
masterBloc.add(MasterToggleInFavorites(item));
},
child: CircleContainer(
child: Icon(
//Icons.playlist_add,
item.isFavorite
? Icons.favorite_border
: Icons.favorite,
color: Colors.white,
),
size: 35,
),
),
我在完成与我应该如何从列表(来自 api 响应)add/remove(切换)收藏夹相关的操作时遇到了一些问题。实际上,我可以将收藏夹添加到列表中,也可以以单独的方式将其删除,但我不能以切换方式使用相同的按钮来完成。简而言之,它正在工作,但我无法正确实现切换操作。请您看一下代码,看看是否有一种好的方法可以在不使用 setstate 的情况下实现切换?
关闭按钮(从列表中删除)
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
onDismissed();
},
child: CircleContainer(
child: Icon(
item.isFavorite
? Icons.favorite
: Icons.favorite_border,
color: Colors.white,
),
size: 35,
),
),
使用 Bloc 实现将收藏夹添加到列表的相同按钮
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
masterBloc.add(MasterAddToFavorites(item));
},
child: CircleContainer(
child: Icon(
item.isFavorite
? Icons.favorite
: Icons.favorite_border,
color: Colors.white,
),
size: 35,
),
),
项目定义
class YoutbeVideo {
final String videoId, title, description, banner;
bool isFavorite;
YoutbeVideo(
{@required this.videoId,
@required this.title,
@required this.description,
@required this.banner,
this.isFavorite});
void toggleFavoriteStatus() {
isFavorite = !isFavorite;
}
BloC 代码分为 3 个文件
master_bloc
import 'package:bloc/bloc.dart';
import 'package:documentales_app/models/youtube_video.dart';
import 'master_events.dart';
import 'master_state.dart';
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 MasterRemoveFromFavorites) {
yield* _removeFromFavorites(event);
} else if (event is MasterLogout) {
yield this.state.copyWith(history: [], currentTab: 0);
} else if (event is MasterAddToFavorites) {
yield* _addToFavorites(event);
}
}
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> _addToFavorites(MasterAddToFavorites 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);
yield this.state.copyWith(favorites: favorites);
}
}
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> _removeFromFavorites(
MasterRemoveFromFavorites event) async* {
final favorites = List<YoutubeVideo>.from(this.state.favorites);
favorites.removeAt(event.index);
yield this.state.copyWith(favorites: favorites);
}
}
主状态
import 'package:meta/meta.dart' show required;
import 'package:documentales_app/models/youtube_video.dart';
import 'package:equatable/equatable.dart';
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 MasterAddToFavorites extends MasterEvents {
final YoutubeVideo youtubeVideo;
MasterAddToFavorites(this.youtubeVideo);
}
class MasterRemoveFromHistory extends MasterEvents {
final int index;
MasterRemoveFromHistory(this.index);
}
class MasterRemoveFromFavorites extends MasterEvents {
final int index;
MasterRemoveFromFavorites(this.index);
}
因此执行切换的一种方法是仅用一个替换添加和删除事件。所以你可以摆脱这些事件:
class MasterAddToFavorites extends MasterEvents {
final YoutubeVideo youtubeVideo;
MasterAddToFavorites(this.youtubeVideo);
}
class MasterRemoveFromFavorites extends MasterEvents {
final int index;
MasterRemoveFromFavorites(this.index);
}
并将其替换为:
class MasterToggleInFavorites extends MasterEvents {
final YoutubeVideo video;
MasterToggleInFavorites(video);
}
接下来,在 bloc 内部,在处理该事件的方法内部,您可以这样做:
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.isFavourite = true;
yield this.state.copyWith(favorites: favorites);
} else {
final favorites = List<YoutubeVideo>.from(this.state.favorites);
favorites.removeAt(index);
event.youtubeVideo.isFavourite = false;
yield this.state.copyWith(favorites: favorites);
}
视频Class
class YoutubeVideo {
final String videoId, title, description, banner;
bool isFavorite;
YoutubeVideo(
{@required this.videoId,
@required this.title,
@required this.description,
@required this.banner,
this.isFavorite = false});
factory YoutubeVideo.fromJson(Map<String, dynamic> json,
{bool fromPlayList = false}) {
final snippet = json['snippet'];
final thumbnail =
snippet['thumbnails']['standard'] ?? snippet['thumbnails']['high'];
String videoId;
if (!fromPlayList) {
videoId = json['contentDetails']['videoId'];
} else {
videoId = snippet['resourceId']['videoId'];
}
return YoutubeVideo(
videoId: videoId,
title: snippet['title'],
description: snippet['description'],
banner: thumbnail['url']);
}
}
这里是 onPressed 动作,但出于任何原因没有反映颜色变化
CupertinoButton(
padding: EdgeInsets.zero,
minSize: 30,
onPressed: () {
masterBloc.add(MasterToggleInFavorites(item));
},
child: CircleContainer(
child: Icon(
//Icons.playlist_add,
item.isFavorite
? Icons.favorite_border
: Icons.favorite,
color: Colors.white,
),
size: 35,
),
),