3

在此处输入图像描述

对于如图所示的仪表板设计,我必须显示从 API 获取的各种计数。每个计数都将通过查看标签从不同的 API 中获取。

我开发的结构,

  • DashboardScreen
    • CustomBottomMenuOptionWidget(标签) -StatelessWidget
      • MenuCountPage(label) - StatefulWidget(为了显示计数,我MenuCountScreen使用了单独的小部件event,并根据标签使用state& )bloc

当应用程序打开时,一切正常。对于每个不同的菜单选项,我可以获得每个标签的计数。我的主要问题是用户在应用程序中前进并创建一个新事件,当返回仪表板时,我如何刷新此计数或简单地说我如何将事件添加到BLoCMenuCountScreen获得更新的值?

当前实施:

仪表板.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);
    }
  }
}

我已经尝试过的事情:

  1. 由父(来自“仪表板”)提供BLoC,当用户返回仪表板时尝试添加事件以获取更新的计数。没用。(如果是因为我有基于标签的不同 API 调用,并且每个计数都与它自己的 MenuCountBloc 实例相关联 - 如果我错了,请清除我)

  2. 尝试获取一个bool值并将其传递给MenuCountScreenfrom Dashboard,当用户返回仪表板时更新该值,bool认为它会刷新并再次调用事件但没有奏效。

  3. 除了尝试过的选项 1,采用 4 个不同的int参数来存储 4 个不同的计数BLoC以及MenuCountState. BLoC以为它会为我提供的4 个值存储Dashboard. 但没有奏效。

    我想知道,我的实现方式是否正确以及我尝试过的事情。也是一个可能的解决方案来完成我被卡住的任务。

编辑: 我推到这里的示例项目:GitHub

4

1 回答 1

0

所以基本上你是在说'当你回到你的旧屏幕然后如何更新值?'

与 BLoC 无关,但与Navigator相关。

如果您注意到,您会看到每个 Navigator.push 函数都返回一个未来。基本上你可以等待,直到你在下一个屏幕上。

当您从下一个屏幕弹出时,您可以来到第一个屏幕,您的 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

于 2020-05-21T15:25:03.777 回答