flutter bloc:点击时改变每个项目的颜色
flutter bloc: change color on each item when tap
我正在尝试使用 flutter bloc,所以我创建了这个 bloc:
class CategoriesBloc extends Bloc<CategoriesEvent, CategoriesState> {
CategoriesBloc() : super(CategoriesInitial());
List<CategoriesItem> _catItems = [
CategoriesItem(id: 1, title: "Sugar", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 2, title: "Calories", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 3, title: "Salt", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 4, title: "Fibre", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 5, title: "Fat", prefixIcon: Icons.access_alarms)
];
List<CategoriesItem> get items => _catItems;
@override
Stream<CategoriesState> mapEventToState(
CategoriesEvent event,
) async* {
if (event is TopCategoriesEvent) {
yield* _makeCatList(items);
}
}
}
Stream<CategoriesState> _makeCatList(List<CategoriesItem> items) async* {
yield CategoriesStarted(items);
}
class CategoriesItem {
final int id;
final String title;
final IconData prefixIcon;
final IconData suffixIcon;
bool selected;
CategoriesItem(
{this.id,
this.title,
this.prefixIcon,
this.suffixIcon,
this.selected = false});
}
现在在主页面我是这样使用的:
Container(
height: 80,
color: Colors.green[500],
child: BlocBuilder<CategoriesBloc, CategoriesState>(
builder: (context, state) {
if (state is CategoriesInitial) {
return Center(
child: CircularProgressIndicator(),
);
} else if (state is CategoriesStarted) {
return _makeCatItems(state.catItems);
}
return Container();
}),
这是我的 _makeCatItems 方法:
Widget _makeCatItems(List<CategoriesItem> catItems) {
print(catItems.length);
return Container(
margin: EdgeInsets.only(top: 8.0),
child: ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: catItems
.map(
(item) => Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () {},
child: Container(
width: 100,
height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Colors.green[300],// change to white when tapped
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(
item.prefixIcon,
color: Colors.white,
),
Text(
item.title,
style: TextStyle(color: Colors.white),
)
],
)),
),
SizedBox(
width: 16.0,
)
],
),
)
.toList(),
),
);
}
当用户以 bloc 方式单击每个项目时,如何更改背景项目颜色?
您可以添加一个点击项目列表,最初为空列表,在该状态下,添加一个传递字段中项目的事件,并将 BoxDecoration 中的颜色更改为 state.tappedItems.contains(item) ? Colors.white : Colors.green[300]
。您也需要更改 onTap,如下所示:
state.tappedItems.contains(item)
? context.bloc<CategoriesBloc>().add(AddItem())
: context.bloc<CategoriesBloc>().add(RemoveItem()),
makeCatItems 还需要获取状态作为参数或成为另一个 BlocBuilder,以您感觉更好为准
E:
将状态更改为(您也需要更改 CategoriesState,在字段中添加 final List<CategoriesItem> pressedItems
)
Stream<CategoriesState> _makeCatList(List<CategoriesItem> items, List<CategoriesItem> pressedItems) async* {
yield CategoriesStarted(items, pressedItems);
}
然后需要添加事件(CategoryRemoved就差不多了,复制改个名字就行)
class CategoryAdded extends CategoryEvent {
final CategoryItem item;
CategoryAdded(CategoryItem item);
}
所以你同时拥有状态和事件,现在 bloc 需要处理这些变化。
@override
Stream<CategoriesState> mapEventToState(
CategoriesEvent event,
) async* {
if (event is TopCategoriesEvent) {
yield* _makeCatList(items);
} else if (event is CategoryAdded) {
yield CategoryState(state.items, state.pressedItems..add(event.item));
} else if (event is CategoryRemoved {
yield CategoryState(state.items, state.pressedItems..remove(event.item));
}
}
现在你的逻辑已经设置好了,现在你只需要更改小部件
Widget _makeCatItems() {
return BlocBuilder<CategoryBloc, CategoryState>(
builder: (context, state) => Container(
margin: EdgeInsets.only(top: 8.0),
child: ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: catItems
.map(
(item) => Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () {context.bloc<CategoryBloc>().add(state.pressedItems.contains(item) ? RemoveCategory(item) : AddCategory(item)},
child: Container(
width: 100,
height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: state.pressedItems.contains(item) ? Colors.white : Colors.green[300],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(
item.prefixIcon,
color: Colors.white,
),
Text(
item.title,
style: TextStyle(color: Colors.white),
)
],
)),
),
SizedBox(
width: 16.0,
)
],
),
)
.toList(),
),
);
);
}
我正在尝试使用 flutter bloc,所以我创建了这个 bloc:
class CategoriesBloc extends Bloc<CategoriesEvent, CategoriesState> {
CategoriesBloc() : super(CategoriesInitial());
List<CategoriesItem> _catItems = [
CategoriesItem(id: 1, title: "Sugar", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 2, title: "Calories", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 3, title: "Salt", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 4, title: "Fibre", prefixIcon: Icons.access_alarms),
CategoriesItem(id: 5, title: "Fat", prefixIcon: Icons.access_alarms)
];
List<CategoriesItem> get items => _catItems;
@override
Stream<CategoriesState> mapEventToState(
CategoriesEvent event,
) async* {
if (event is TopCategoriesEvent) {
yield* _makeCatList(items);
}
}
}
Stream<CategoriesState> _makeCatList(List<CategoriesItem> items) async* {
yield CategoriesStarted(items);
}
class CategoriesItem {
final int id;
final String title;
final IconData prefixIcon;
final IconData suffixIcon;
bool selected;
CategoriesItem(
{this.id,
this.title,
this.prefixIcon,
this.suffixIcon,
this.selected = false});
}
现在在主页面我是这样使用的:
Container(
height: 80,
color: Colors.green[500],
child: BlocBuilder<CategoriesBloc, CategoriesState>(
builder: (context, state) {
if (state is CategoriesInitial) {
return Center(
child: CircularProgressIndicator(),
);
} else if (state is CategoriesStarted) {
return _makeCatItems(state.catItems);
}
return Container();
}),
这是我的 _makeCatItems 方法:
Widget _makeCatItems(List<CategoriesItem> catItems) {
print(catItems.length);
return Container(
margin: EdgeInsets.only(top: 8.0),
child: ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: catItems
.map(
(item) => Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () {},
child: Container(
width: 100,
height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: Colors.green[300],// change to white when tapped
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(
item.prefixIcon,
color: Colors.white,
),
Text(
item.title,
style: TextStyle(color: Colors.white),
)
],
)),
),
SizedBox(
width: 16.0,
)
],
),
)
.toList(),
),
);
}
当用户以 bloc 方式单击每个项目时,如何更改背景项目颜色?
您可以添加一个点击项目列表,最初为空列表,在该状态下,添加一个传递字段中项目的事件,并将 BoxDecoration 中的颜色更改为 state.tappedItems.contains(item) ? Colors.white : Colors.green[300]
。您也需要更改 onTap,如下所示:
state.tappedItems.contains(item)
? context.bloc<CategoriesBloc>().add(AddItem())
: context.bloc<CategoriesBloc>().add(RemoveItem()),
makeCatItems 还需要获取状态作为参数或成为另一个 BlocBuilder,以您感觉更好为准
E:
将状态更改为(您也需要更改 CategoriesState,在字段中添加 final List<CategoriesItem> pressedItems
)
Stream<CategoriesState> _makeCatList(List<CategoriesItem> items, List<CategoriesItem> pressedItems) async* {
yield CategoriesStarted(items, pressedItems);
}
然后需要添加事件(CategoryRemoved就差不多了,复制改个名字就行)
class CategoryAdded extends CategoryEvent {
final CategoryItem item;
CategoryAdded(CategoryItem item);
}
所以你同时拥有状态和事件,现在 bloc 需要处理这些变化。
@override
Stream<CategoriesState> mapEventToState(
CategoriesEvent event,
) async* {
if (event is TopCategoriesEvent) {
yield* _makeCatList(items);
} else if (event is CategoryAdded) {
yield CategoryState(state.items, state.pressedItems..add(event.item));
} else if (event is CategoryRemoved {
yield CategoryState(state.items, state.pressedItems..remove(event.item));
}
}
现在你的逻辑已经设置好了,现在你只需要更改小部件
Widget _makeCatItems() {
return BlocBuilder<CategoryBloc, CategoryState>(
builder: (context, state) => Container(
margin: EdgeInsets.only(top: 8.0),
child: ListView(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
children: catItems
.map(
(item) => Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
InkWell(
onTap: () {context.bloc<CategoryBloc>().add(state.pressedItems.contains(item) ? RemoveCategory(item) : AddCategory(item)},
child: Container(
width: 100,
height: 40,
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8.0),
color: state.pressedItems.contains(item) ? Colors.white : Colors.green[300],
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Icon(
item.prefixIcon,
color: Colors.white,
),
Text(
item.title,
style: TextStyle(color: Colors.white),
)
],
)),
),
SizedBox(
width: 16.0,
)
],
),
)
.toList(),
),
);
);
}