问题
How would one load a set of local images for display in a widget (noting this is async - see function below) triggered by (based on) a change in state from a flutter_bloc for “settings”? Noting this bloc is persisted too via hydrated_bloc. So the use case for which I’m asking how do I code this in flutter (noting I’m using flutter_bloc) is:
Use Case - Render different set of images on the same Widget I have for dynamically displaying a room for a 2D point & click adventure type game, BASED ON the “room” the user goes to. A change in room event is passed to a SettingsBloc which will then determine the new “room” to move to. This new “room” state is available via the Bloc concept, however how & where do I then do the async load of the specific set of images I need for this room (nothing they are set at compile time)? (To feed it to the dynamic room rendering widget with a CustomPainter that I have - i.e. images painted onto canvas).
For example which approach is recommended to do this? (then ideally what the code looks like to achive this)
a) Listen for a change in “room” within the widget, and then trigger (within a widget) to call the async function to dynamically load the ui.Image’s that I need? But if yes, how do you do this in code within a Widget? (or is this not best practice). Refer my code below which does work/run but seems to have a infinite loop happening OR
b) Should I setup Images as a separate bloc (e.g. images_bloc). But in this case what is the flutter code that would be required to do this: i.e.
- user does something in UI that triggers an event & passes it to SettingsBloc
- the SettingsBloc then may determine there is a change in "room" due to this and change/emit the new "currentRoom"
- the SettingsBloc would then then to trigger an aynch request to ImagesBlock (somehow) get the new List of ui.Images for this "room", using the async code below
- The UI/Widget then needs to pickup the changes for “String room” and List of ui.Image’s
c) Another approach?
Here is my best try at approach (a) above so far. Works in UI re changing background, however there seems to be an infinite loop:
Logging:
Launching lib/main.dart on iPhone 12 Pro Max in debug mode...
lib/main.dart:1
Xcode build done. 29.5s
Connecting to VM Service at ws://127.0.0.1:49364/lyUIDblZgmY=/ws
flutter: game_main.build ----------------------------
flutter: trying to get room data for current room: room2
flutter: About to load imagename:plane.png
flutter: game_main.build ----------------------------
flutter: trying to get room data for current room: room2
flutter: About to load imagename:plane.png
flutter: game_main.build ----------------------------
flutter: trying to get room data for current room: room2
flutter: About to load imagename:plane.png
flutter: game_main.build ----------------------------
ETC ETC
Code:
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:adventure/ui/widgets/game_painter.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:adventure/bloc/settings_cubit.dart';
import 'package:adventure/game_design/room.dart';
import 'package:flutter/material.dart';
import 'package:touchable/touchable.dart';
class GameMain extends StatefulWidget {
GameMain({Key key}) : super(key: key);
@override
_GameMainState createState() => _GameMainState();
}
class _GameMainState extends State<GameMain> {
final RoomsData roomsData = RoomsData.getPopulated();
ui.Image _backgroundImage;
Future<ui.Image> _loadImageAsync(imageString) async {
ByteData bd = await rootBundle.load(imageString);
final Uint8List bytes = Uint8List.view(bd.buffer);
final ui.Codec codec = await ui.instantiateImageCodec(bytes);
final ui.Image image = (await codec.getNextFrame()).image;
return image;
}
Future<void> _updateBackgroundImageState(String imagename) async {
print('About to load imagename:$imagename');
final image = await _loadImageAsync('assets/images/$imagename');
setState(() {
_backgroundImage = image;
});
}
@override
Widget build(BuildContext context) {
print('game_main.build ----------------------------');
// Get Persistant Data Settings
SettingsCubit settingsCubit = context.watch<SettingsCubit>();
// Get Room Configuration (for room we're now in)
print('Trying to get room data for current room: ${settingsCubit.state.currentRoom}');
Room roomData = roomsData.getRoom(settingsCubit.state.currentRoom);
// Update Background Image
_updateBackgroundImageState(roomData.backgroundImage);
// Create and return Canvas
return Container(
child: BlocBuilder<SettingsCubit, SettingsState>(
builder: (context, state) {
return Stack(children: <Widget>[
CanvasTouchDetector(
builder: (context) => CustomPaint(
painter: GamePainter(context, settingsCubit, roomData, _backgroundImage)
)
),
FlatButton(
// For testing changes to background image
color: Colors.blue,
textColor: Colors.white,
onPressed: () {
var newRoomString = settingsCubit.state.currentRoom == 'room1' ? 'room2' : 'room1';
settingsCubit.setRoom(newRoomString);
},
child: Text(
"Flat Button",
style: TextStyle(fontSize: 20.0),
),
),
]);
}
)
);
}
}
来源:https://stackoverflow.com/questions/65856448/flutter-bloc-and-how-a-bloc-state-change-can-then-trigger-a-2nd-async-call-befor