Reputation: 2418
I have a screen that creates a widget.
How can I add a bloc to my widget?
class UserView extends StatelessWidget {
final AnimationController aController;
final Animation animation;
@override
Widget build(BuildContext context) {
// Add Scafold here?
return AnimationBuilder(
animation: aController;
builder: (BuildContext context, Widget child) {
...
},
);
}
}
The bloc
class UserBloc extends Bloc<UserEvent, UserState> {
final UserRepo userRepo;
UserBloc({@required this.userRepo}) : assert(userRepo != null);
}
If I add a Scaffold()
then I get an error saying "object was given an infinite size during layout".
I am using this https://bloclibrary.dev/#/ for bloc.
I can show more code if necessary, I am trying to keep it light for easy reading. Please ask and I can add more.
App
void main() async {
final UserRepo userRepo = UserRepo();
BlocSupervisor.delegate = SimpleBlocDelegate();
WidgetsFlutterBinding.ensureInitialized();
await SystemChrome.setPreferredOrientations(<DeviceOrientation>[
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown
]).then((_) => runApp(MultiBlocProvider(
providers: [
BlocProvider<UserBloc>(
create: (context) => UserBloc(userRepo: userRepo),
)
],
child: MyApp(),
)));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
textTheme: AppTheme.textTheme,
platform: TargetPlatform.iOS,
),
home: HomeScreen(),
);
}
}
Home Screen
class HomeScreen extends StatefulWidget {
@override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen>
with TickerProviderStateMixin {
AnimationController animationController;
Widget tabBody = Container(
color: AppTheme.background,
);
@override
void initState() {
animationController = AnimationController(
duration: const Duration(milliseconds: 800), vsync: this);
tabBody = DashboardScreen(animationController: animationController);
super.initState();
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: AppTheme.background,
child: Scaffold(
backgroundColor: Colors.transparent,
body: FutureBuilder<bool>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData) {
return const SizedBox();
} else {
return Stack(
children: <Widget>[
tabBody
],
);
}
},
),
),
);
}
}
Dashboard
class DashboardScreen extends StatefulWidget {
const DashboardScreen({Key key, this.animationController}) : super(key: key);
final AnimationController animationController;
@override
_DashboardScreenState createState() => _DashboardScreenState();
}
class _DashboardScreenState extends State<DashboardScreen>
with TickerProviderStateMixin {
Animation<double> topBarAnimation;
List<Widget> listViews = <Widget>[];
final ScrollController scrollController = ScrollController();
double topBarOpacity = 0.0;
@override
void initState() {
listViews.add(
UserView(
animation: Tween<double>(begin: 0.0, end: 1.0).animate(CurvedAnimation(
parent: widget.animationController,
curve:
Interval((1 / count) * 1, 1.0, curve: Curves.fastOutSlowIn))),
animationController: widget.animationController,
),
);
super.initState();
}
}
Upvotes: 1
Views: 486
Reputation: 4109
I will suppose that UserBloc
must be available to the whole app, if not, just change the level of the provider below to be just above the widgets it should cover:
Here you provide the bloc to be above MaterialApp
widget to be order to use it later in any descendant of this widget:(inside App file)
return BlocProvider(
create: (_)=>UserBloc(userRepo:UserRep()),
child: MaterialApp(
title: 'Test App',
theme: ThemeData(
primarySwatch: Colors.blue,
textTheme: AppTheme.textTheme,
platform: TargetPlatform.iOS,
),
home: HomeScreen(),
),
);
now if you want to use your bloc to emit events and listen to states in any descendant widget of MaterialApp
, you just wrap that widget with a BlocListener
or BlocConsumer
or BlocBuilder
(see difference between them here):
I will suppose you want to do that in HomeScreen
:
class _HomeScreenState extends State<HomeScreen>
with TickerProviderStateMixin {
AnimationController animationController;
Widget tabBody = Container(
color: AppTheme.background,
);
@override
void initState() {
animationController = AnimationController(
duration: const Duration(milliseconds: 800), vsync: this);
tabBody = DashboardScreen(animationController: animationController);
super.initState();
}
@override
void dispose() {
animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Container(
color: AppTheme.background,
child: Scaffold(
backgroundColor: Colors.transparent,
body: FutureBuilder<bool>(
future: getData(),
builder: (BuildContext context, AsyncSnapshot<bool> snapshot) {
if (!snapshot.hasData) {
return const SizedBox();
} else {
return Stack(
children: <Widget>[
//tabBody
//Don't save widgets as fields, just create them on the fly
BlocBuilder<UserBloc,UserState>(
builder: (ctx,state){
//return widget that depends on state and which should rebuild when state changes
return DashboardScreen(animationController: animationController);
},
)
],
);
}
},
),
),
);
}
}
and that's it.
Check the link above for more documentation.
Upvotes: 1