- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于如图所示的仪表板设计,我必须显示从 API 获取的各种计数。每个计数都将通过查看标签从不同的 API 获取。
我开发的结构,
DashboardScreen
CustomBottomMenuOptionWidget
(标签)- StatelessWidget
MenuCountPage
(标签)- StatefulWidget
(为了显示计数,我根据标签采用了单独的 MenuCountScreen
小部件及其自己的 event
、state
和 bloc
)当应用程序打开时,一切正常。对于每个不同的菜单选项,我都可以获得每个标签的计数。我的主要问题是用户在应用程序中前进并创建一个新事件,当返回仪表板时,我如何刷新此计数或简单地说我如何将事件添加到 BLoC
的 MenuCountScreen
获得更新值?
当前实现:
dashboard.dart( GridView )
GridView.count(
primary: false,
padding: const EdgeInsets.all(20),
crossAxisSpacing: 20,
mainAxisSpacing: 20,
crossAxisCount: 2,
childAspectRatio: 1.3,
children: <Widget>[
HomeBottomGridMenuItem(
label: kMenuLabelCalendar,
onItemClick: () {
_onTapHomeMenuItem(context, kMenuLabelCalendar);
},
icon: ICON_CALENDAR,
itemCountExist: true,
itemCount: 10,
),
...other menu item
)
HomeBottomGridMenuItem.dart
import 'package:flutter/material.dart';
import 'package:flutter_app/resources/colors.dart';
import 'package:flutter_app/screens/dashboard/menu_count/menu_count.dart';
class HomeBottomGridMenuItem extends StatelessWidget {
final String label;
final String icon;
final Function onItemClick;
final bool itemCountExist;
final int itemCount;
HomeBottomGridMenuItem({
this.label,
this.icon,
this.onItemClick,
this.itemCountExist,
this.itemCount,
});
@override
Widget build(BuildContext context) {
return Stack(
fit: StackFit.expand,
children: <Widget>[
InkWell(
onTap: onItemClick,
splashColor: Colors.black26,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 8.0,
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
),
borderRadius: BorderRadius.all(
Radius.circular(
8.0,
),
),
),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Image.asset(
icon,
height: 40.0,
width: 40.0,
color: kColorDashboardMenuItemIcon,
),
Text(
label,
textAlign: TextAlign.start,
style: Theme.of(context).textTheme.headline4.copyWith(
fontWeight: FontWeight.w400,
color: kColorDashboardMenuItemLabel,
),
)
],
),
),
),
Positioned(
top: 0,
right: 0,
child: Visibility(
visible: itemCountExist,
child: Container(
padding: EdgeInsets.symmetric(
horizontal: 14.0,
vertical: 5.0,
),
decoration: BoxDecoration(
color: kColorAppPrimaryBlackShade,
borderRadius: BorderRadius.only(
topRight: Radius.circular(
5.0,
),
bottomLeft: Radius.circular(
5.0,
),
),
),
child: MenuCountPage(
label: label,
),
),
),
),
],
);
}
}
MenuCountPage.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'menu_count.dart';
class MenuCountPage extends StatelessWidget {
final String label;
MenuCountPage({
@required this.label,
});
@override
Widget build(BuildContext context) {
return BlocProvider<MenuCountBloc>(
create: (context) {
return MenuCountBloc(context: context);
},
child: MenuCountScreen(
menuLabel: label,
),
);
}
}
MenuCountScreen.dart
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_app/widgets/loader_circular.dart';
import 'menu_count.dart';
class MenuCountScreen extends StatefulWidget {
final String menuLabel;
MenuCountScreen({
@required this.menuLabel,
});
@override
_MenuCountScreenState createState() => _MenuCountScreenState();
}
class _MenuCountScreenState extends State<MenuCountScreen> {
MenuCountBloc _menuCountBloc;
@override
void initState() {
_menuCountBloc = BlocProvider.of<MenuCountBloc>(context);
_menuCountBloc.add(
GetMenuCount(menuLabel: widget.menuLabel),
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Center(
child: BlocBuilder<MenuCountBloc, MenuCountState>(
builder: (context, state) {
if (state is MenuCountSuccess) {
return Text(
'${state.count}',
style: Theme.of(context).textTheme.headline2.copyWith(
color: Colors.white,
),
);
}
if (state is MenuCountFail) {
return Text(
'0',
style: Theme.of(context).textTheme.headline2.copyWith(
color: Colors.white,
),
);
}
return CircularLoader(
size: 25,
strokeWidth: 3,
color: Colors.white60,
);
},
),
);
}
}
MenuCountEvent.dart
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class MenuCountEvent extends Equatable {
const MenuCountEvent();
}
class GetMenuCount extends MenuCountEvent {
final String menuLabel;
GetMenuCount({@required this.menuLabel});
@override
List<Object> get props => [];
}
MenuCountState.dart
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class MenuCountState extends Equatable {
const MenuCountState();
@override
List<Object> get props => [];
}
class MenuCountInitial extends MenuCountState {}
class MenuCountLoading extends MenuCountState {}
class MenuCountSuccess extends MenuCountState {
final int count;
MenuCountSuccess({@required this.count});
@override
List<Object> get props => [count];
}
class MenuCountFail extends MenuCountState {}
MenuCountBloc.dart
import 'package:chopper/chopper.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_app/api/api_service.dart';
import 'package:flutter_app/models/dashboard_count_responses/events_count_response.dart';
import 'package:flutter_app/models/dashboard_count_responses/open_ticket_count_response.dart';
import 'package:flutter_app/models/dashboard_count_responses/properties_count_response.dart';
import 'package:flutter_app/resources/strings.dart';
import 'package:flutter_app/utility/sharedpref_helper.dart';
import 'package:provider/provider.dart';
import 'menu_count.dart';
class MenuCountBloc extends Bloc<MenuCountEvent, MenuCountState> {
final BuildContext context;
MenuCountBloc({@required this.context});
@override
MenuCountState get initialState => MenuCountInitial();
@override
Stream<MenuCountState> mapEventToState(MenuCountEvent event) async* {
if (event is GetMenuCount) {
yield MenuCountLoading();
if (event.menuLabel.length > 0) {
yield* _getCountValueByLabel(event.menuLabel);
}
}
}
Stream<MenuCountState> _getCountValueByLabel(String menuLabel) async* {
switch (menuLabel) {
case kMenuLabelOpenTickets:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<OpenTicketCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getOpenTicketCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.openTickets);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
case kMenuLabelProperties:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<PropertiesCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getPropertiesCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.properties_active);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
case kMenuLabelCalendar:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<EventsCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getEventsCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.events);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
case kMenuLabelAllTickets:
try {
final String token = await SharedPreferenceHelper.getToken();
final Response<OpenTicketCountResponse> apiResponse =
await Provider.of<ApiService>(context, listen: false)
.getOpenTicketCount(token);
if (apiResponse.isSuccessful) {
yield MenuCountSuccess(count: apiResponse.body.tickets);
} else {
print('API : Response Failed');
yield MenuCountSuccess(count: 0);
}
} catch (exception) {
print('Exception: ${exception.toString()}');
yield MenuCountSuccess(count: 0);
}
break;
default:
yield MenuCountSuccess(count: 0);
}
}
}
我已经尝试过的事情:
提供 BLoC
来自父级(来自“仪表板”)并且当用户返回仪表板时尝试添加事件以获取更新计数。没用。 (如果是因为我有不同的基于标签的 API 调用并且每个计数都与其自己的 MenuCountBloc 实例相关联 - 如果我错了请清除我)
尝试拍摄 bool
值并将其传递给 MenuCountScreen
来自 Dashboard
当用户返回仪表板时,更新 bool
的值认为它会刷新并再次调用事件但没有奏效。
除了尝试过的选项 1,取 4 个不同的 int
在 BLoC
中存储 4 个不同计数的参数以及 MenuCountState
.以为它会为 BLoC
存储 4 个值我从 Dashboard
提供的.但没有成功。
我想知道,我的实现方式是否正确以及我尝试过的事情。也是一种可能的解决方案,可以在我遇到困难时完成我的任务。
已编辑:我在此处推送的示例项目:GitHub
最佳答案
所以基本上你是在说'当你回到旧屏幕时如何更新值?'
它与 BLoC 无关,但与Navigators 相关。
如果您注意到,您会看到每个 Navigator.push 函数都返回一个 future 。基本上您可以等待直到您进入下一个屏幕。
当您从下一个屏幕弹出时,您可以来到第一个屏幕,您的 Navigator.push 会告诉您下一个屏幕已关闭。
让我们看一些代码。
class _AState extends State<A> {
void gotoB() async {
await Navigator.push(context, MaterialPageRoute(builder: (context) => B()));
refreshScreen();
}
void refreshScreen() {
// Call BLoC functions to update the screen
}
@override
Widget build(BuildContext context) {
return Container();
}
}
class B extends StatefulWidget {
@override
_BState createState() => _BState();
}
class _BState extends State<B> {
completeWork() {
Navigator.pop(context);
}
@override
Widget build(BuildContext context) {
return Container();
}
}
从A类我要去B类。我在Navigator前面使用await等待我从B回来。
当我在执行 Navigator.pop() 时从 B 返回到 A。来到这里后,我正在刷新我的屏幕 A。
关于flutter - 如何刷新 Flutter 应用程序仪表板上的计数值? (遵循 BLoC 模式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61889399/
对此感到疯狂,真的缺少一些东西。 我有webpack 4.6.0,webpack-cli ^ 2.1.2,所以是最新的。 在文档(https://webpack.js.org/concepts/mod
object Host "os.google.com" { import "windows" address = "linux.google.com" groups = ["linux"] } obj
每当我安装我的应用程序时,我都可以将数据库从 Assets 文件夹复制到 /data/data/packagename/databases/ .到此为止,应用程序工作得很好。 但 10 或 15 秒后
我在 cc 模式缓冲区中使用 hideshow.el 来折叠我不查看的文件部分。 如果能够在 XML 文档中做到这一点就好了。我使用 emacs 22.2.1 和内置的 sgml-mode 进行 xm
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
根据java: public Scanner useDelimiter(String pattern) Sets this scanner's delimiting pattern to a patt
我读过一些关于 PRG 模式以及它如何防止用户重新提交表单的文章。比如this post有一张不错的图: 我能理解为什么在收到 2xx 后用户刷新页面时不会发生表单提交。但我仍然想知道: (1) 如果
看看下面的图片,您可能会清楚地看到这一点。 那么如何在带有其他一些 View 的简单屏幕中实现没有任何弹出/对话框/模式的微调器日期选择器? 我在整个网络上进行了谷歌搜索,但没有找到与之相关的任何合适
我不知道该怎么做,我一直遇到问题。 以下是代码: rows = int(input()) for i in range(1,rows): for j in range(1,i+1):
我想为重写创建一个正则表达式。 将所有请求重写为 index.php(不需要匹配),它不是以/api 开头,或者不是以('.html',或'.js'或'.css'或'.png'结束) 我的例子还是这样
MVC模式代表 Model-View-Controller(模型-视图-控制器) 模式 MVC模式用于应用程序的分层开发 Model(模型) - 模型代表一个存取数据的对象或 JAVA PO
我想为组织模式创建一个 RDF 模式世界。您可能知道,组织模式文档基于层次结构大纲,其中标题是主要的分组实体。 * March auxiliary :PROPERTIES: :HLEVEL: 1 :E
我正在编写一个可以从文件中读取 JSON 数据的软件。该文件包含“person”——一个值为对象数组的对象。我打算使用 JSON 模式验证库来验证内容,而不是自己编写代码。符合代表以下数据的 JSON
假设我有 4 张 table 人 公司 团体 和 账单 现在bills/persons和bills/companys和bills/groups之间是多对多的关系。 我看到了 4 种可能的 sql 模式
假设您有这样的文档: doc1: id:1 text: ... references: Journal1, 2013, pag 123 references: Journal2, 2014,
我有这个架构。它检查评论,目前工作正常。 var schema = { id: '', type: 'object', additionalProperties: false, pro
这可能很简单,但有人可以解释为什么以下模式匹配不明智吗?它说其他规则,例如1, 0, _ 永远不会匹配。 let matchTest(n : int) = let ran = new Rand
我有以下选择序列作为 XML 模式的一部分。理想情况下,我想要一个序列: 来自 my:namespace 的元素必须严格解析。 来自任何其他命名空间的元素,不包括 ##targetNamespace和
我希望编写一个 json 模式来涵盖这个(简化的)示例 { "errorMessage": "", "nbRunningQueries": 0, "isError": Fals
首先,我是 f# 的新手,所以也许答案很明显,但我没有看到。所以我有一些带有 id 和值的元组。我知道我正在寻找的 id,我想从我传入的三个元组中选择正确的元组。我打算用两个 match 语句来做到这
我是一名优秀的程序员,十分优秀!