英文:
How do i make my bloc work in a reusable widget created?
问题
你遇到的问题是因为GlassPlayerCard
组件内部使用了BlocProvider.of<MusicControlBloc>(context)
来获取MusicControlBloc
,但是在GlassPlayerCard
所在的上下文中找不到MusicControlBloc
。为了解决这个问题,你可以尝试以下几种方法:
-
将
BlocProvider<MusicControlBloc>
包装在MyApp
中:在
MyApp
中包装BlocProvider
,以便整个应用程序都可以访问MusicControlBloc
。你已经在main.dart
中使用MultiProvider
包装MyApp
,但似乎忽略了MusicControlBloc
的提供。确保在providers
列表中添加BlocProvider
来提供MusicControlBloc
。 -
将
GlassPlayerCard
从context
中独立出来:如果
GlassPlayerCard
是在某个具有context
的子部件中使用的,你可以尝试将GlassPlayerCard
提升到更高层次的部件,以便它可以访问到MusicControlBloc
。这可以通过在包含GlassPlayerCard
的父部件中使用BlocProvider.of<MusicControlBloc>(context)
来实现。 -
通过构造函数传递
MusicControlBloc
:你可以尝试将
MusicControlBloc
作为GlassPlayerCard
的构造函数参数传递,而不是从context
中获取它。这样,你可以在创建GlassPlayerCard
实例时将MusicControlBloc
传递给它,而不必依赖context
。确保在使用GlassPlayerCard
的地方将MusicControlBloc
传递给它。
以下是一些可能的解决方法,你可以根据你的项目结构和需求选择其中一个或多个来解决上述问题。希望这些建议有助于解决你的上下文错误问题。
英文:
I have a reusable widget I created below as part of a UI for my app
The code for the reusable widget is below
// ignore_for_file: prefer_typing_uninitialized_variables
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:musica/musica/domain/entities/riverpod_file.dart';
import 'package:musica/musica/presentation/manager/music_control_bloc.dart';
import 'package:musica/musica/presentation/widgets/constants.dart';
import 'package:musica/musica/presentation/widgets/reused_widgets/glassmorphism.dart';
import 'package:provider/provider.dart';
class GlassPlayerCard extends StatelessWidget {
final String currentPlayingMusicTitle;
final String musicArtist;
final String imageLink;
final MusicControlBloc? musicControlBloc;
GlassPlayerCard(
{required this.currentPlayingMusicTitle,
required this.musicArtist,
required this.imageLink,
this.musicControlBloc})
: super(key: UniqueKey());
@override
Widget build(BuildContext context) {
final musicBloc = BlocProvider.of<MusicControlBloc>(context);
final musicPlayerProvider = Provider.of<MusicPlayerProvider>(context);
return GlassMorphicContainer(
500.0,
100.0,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
addHorizontalSpacing(10),
Column(
children: [
addVerticalSpacing(15),
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: textColor, width: 2)),
height: 60,
width: 60,
child: Image.network(
imageLink,
),
),
),
],
),
addHorizontalSpacing(10),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
addVerticalSpacing(10),
Text(currentPlayingMusicTitle,
overflow: TextOverflow.ellipsis,
style: mediumWhiteTextStyle),
Text(musicArtist,
style:
smallWhiteTextStyle.copyWith(color: textColor)),
],
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
// GestureDetector(
// onTap: () {
// musicPlayerProvider.pauseMusic();
// },
// child: I
// con(Icons.pause, color: textColor)),
addHorizontalSpacing(10),
BlocBuilder<MusicControlBloc, MusicControlState>(
builder: (context, state) {
if (state is MusicControlInitialState) {
return GestureDetector(
onTap: () {
musicBloc.add(MusicControlPlayEvent());
},
child: Icon(Icons.play_arrow, color: textColor));
} else if (state is MusicControlLoadingState) {
return const Center(
child: CircularProgressIndicator(
color: kDefaultIconDarkColor,
value: 0.5,
strokeWidth: 2,
key: Key('musicLoading'),
),
);
} else if (state is MusicControlPlayingState) {
return GestureDetector(
onTap: () {
musicBloc.add(MusicControlPlayEvent());
},
child: Icon(Icons.pause, color: textColor));
} else {
return Container();
}
}),
addHorizontalSpacing(10),
Icon(Icons.skip_previous, color: textColor),
addHorizontalSpacing(20),
Icon(Icons.skip_next, color: textColor),
addHorizontalSpacing(50),
],
),
],
));
}
}
I used it in my ui app as below
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:musica/generated/assets.dart';
import 'package:musica/musica/domain/entities/riverpod_file.dart';
import 'package:musica/musica/presentation/manager/music_control_bloc.dart';
import 'package:musica/musica/presentation/widgets/constants.dart';
import 'package:musica/musica/presentation/widgets/reused_widgets/animated_like_button.dart';
import 'package:musica/musica/presentation/widgets/reused_widgets/custom_app_bar.dart';
import 'package:musica/musica/presentation/widgets/reused_widgets/glass_player_card.dart';
import 'package:musica/musica/presentation/widgets/reused_widgets/music_card_widget.dart';
import 'package:provider/provider.dart';
class CollectionDetailsWrapper extends StatelessWidget {
const CollectionDetailsWrapper({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => MusicControlBloc(),
);
}
}
class CollectionDetailsPage extends StatefulWidget {
final String imageUrl;
final String title;
final String artistName;
final int fans;
final String trackList;
const CollectionDetailsPage(
{Key? key,
required this.imageUrl,
required this.title,
required this.artistName,
required this.fans,
required this.trackList})
: super(key: key);
@override
State<CollectionDetailsPage> createState() => _CollectionDetailsPageState();
}
class _CollectionDetailsPageState extends State<CollectionDetailsPage> {
MusicPlayerProvider musicPlayerProvider = MusicPlayerProvider();
late Future trackListFuture;
final audioPlayer = AudioPlayer();
bool isPlaying = false;
Duration position = const Duration(seconds: 0);
Duration duration = const Duration(seconds: 0);
String currentPlayingMusicTitle = '';
String currentPlayingMusicArtist = '';
String currentTrackLink = '';
@override
void initState() {
super.initState();
trackListFuture = musicPlayerProvider.getTrackList(widget.trackList);
audioPlayer.onPlayerStateChanged.listen((event) {
setState(() {
isPlaying = event == PlayerState.playing;
});
});
audioPlayer.onDurationChanged.listen((newDuration) {
setState(() {
duration = newDuration;
});
});
audioPlayer.onPositionChanged.listen((newPosition) {
setState(() {
position = newPosition;
});
});
}
@override
Widget build(BuildContext context) {
final musicProvider =
Provider.of<MusicPlayerProvider>(context, listen: false);
final height = MediaQuery.of(context).size.height;
return Scaffold(
bottomNavigationBar: GlassPlayerCard(
imageLink: widget.imageUrl,
currentPlayingMusicTitle: currentPlayingMusicTitle,
musicArtist: currentPlayingMusicArtist,
),
extendBodyBehindAppBar: true,
extendBody: true,
appBar: const PreferredSize(
preferredSize: Size.fromHeight(50), child: CustomAppBar()),
body: Column(
children: [
Stack(clipBehavior: Clip.none, children: <Widget>[
Container(
decoration: BoxDecoration(
color: Colors.transparent,
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
widget.imageUrl,
),
),
),
height: height,
),
Container(
height: height,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: [
backgroundColor,
Colors.transparent.withOpacity(0.5),
],
stops: const [0.5, 0.9],
)),
),
Positioned.fill(
child: ListView(
scrollDirection: Axis.vertical,
children: [
Column(
children: [
Container(
height: 234,
width: 360,
decoration: BoxDecoration(
color: backgroundColor,
borderRadius: BorderRadius.circular(20),
image: DecorationImage(
image: NetworkImage(widget.imageUrl),
fit: BoxFit.cover,
),
),
),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
widget.title,
style: const TextStyle(
color: Color(0xffa4c7c6), fontSize: 25),
),
),
addVerticalSpacing(10),
Padding(
padding: const EdgeInsets.only(left: 20),
child: Text(
widget.artistName,
style: const TextStyle(
color: Color(0xffa4c7c6), fontSize: 15),
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: Image.asset(
Assets.iconsPlayAllIcon,
height: 36,
)),
addHorizontalSpacing(5),
Expanded(
child: Image.asset(
Assets.iconsAddToCollecIcon,
height: 36,
)),
addHorizontalSpacing(5),
const Expanded(
child: AnimatedLikeButton(
text: "Like",
animationPath:
Assets.lottieAnimationsLike)),
],
),
),
],
),
SizedBox(
height: height - 510,
child: FutureBuilder(
future: trackListFuture,
initialData: const Center(
child: CircularProgressIndicator(
color: Colors.white,
backgroundColor: Colors.white,
)),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text(
'Something went wrong',
style: mediumWhiteTextStyle,
));
}
if (snapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(
color: textColor,
),
);
}
return ListView.builder(
shrinkWrap: true,
physics: const ScrollPhysics(),
itemCount: musicPlayerProvider.musicList.length,
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return MusicCardWidget(
name: musicPlayerProvider.musicList[index].name,
artist:
musicPlayerProvider.musicList[index].artist,
duration: musicPlayerProvider
.musicList[index].duration,
trackLink:
musicPlayerProvider.musicList[index].link,
onTapped: () {
musicProvider.playMusic(musicPlayerProvider
.musicList[index].link);
setState(() {
currentPlayingMusicArtist =
musicPlayerProvider
.musicList[index].artist;
currentPlayingMusicTitle =
musicPlayerProvider
.musicList[index].name;
currentTrackLink = musicPlayerProvider
.musicList[index].link;
});
},
);
},
);
}),
)
],
),
)
]),
],
),
);
}
}
Now the problem is I keep getting context errors
The following assertion was thrown building GlassPlayerCard-[#fc2aa](dirty):
BlocProvider.of() called with a context that does not contain a MusicControlBloc.
No ancestor could be found starting from the context that was passed to BlocProvider.of<MusicControlBloc>().
This can happen if the context you used comes from a widget above the BlocProvider.
The context used was: GlassPlayerCard-[#fc2aa](dirty)
irrespective of where I place the bloc provider that provides the bloc to the rest of the app. Even wrapping my main MyApp function with the bloc provider doesn't work.
I tried to add the bloc as a constructor to the reusable widget GlassPlayerCard but it didnt solve the problem. Kindly assist, please.
This is my main.dart
import 'package:flutter/material.dart';
import 'package:musica/musica/domain/entities/riverpod_file.dart';
import 'package:musica/musica/presentation/pages/screens/home.dart';
import 'package:provider/provider.dart';
void main() {
runApp(MultiProvider(
builder: (context, _) {
return const MyApp();
},
providers: [
ChangeNotifierProvider(create: (context) => MusicPlayerProvider()),
],
));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
);
}
}
答案1
得分: 1
你的代码中实际上没有将 bloc 传递给 GlassPlayerCard
。原因是你创建了一个 CollectionDetailsWrapper
,其中包含一个 BlocProvider
,但从你展示的代码片段中看,你实际上没有在任何地方使用它。你还需要传递一个 Widget 子属性,以便将详细信息页面添加为子元素。
确保你将 CollectionDetailsPage
包装在 CollectionDetailsWrapper
中,就像这样:
// 你的新包装定义
class CollectionDetailsWrapper extends StatelessWidget {
final Widget child;
const CollectionDetailsWrapper({Key? key, required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => MusicControlBloc(),
child: child,
);
}
}
/// 你在声明详细信息页面的任何地方的新实现
...
CollectionDetailsWrapper(
child: CollectionDetailsPage(...),
),
...
注意:以上只是代码的翻译部分,没有其他内容。
英文:
Nowhere in your code you are actually passing the bloc to the GlassPlayerCard
. Reason is you created a CollectionDetailsWrapper
That contains a BlocProvider
, but you're not really using it anywhere (at least from the snippets you've shown). You also need to pass in a Widget child property so you can add the details page as the child
Make sure you are Wrapping your CollectionDetailsPage
with your CollectionDetailsWrapper
and that should do it. Like this:
// Your new wrapper definition
class CollectionDetailsWrapper extends StatelessWidget {
final Widget child;
const CollectionDetailsWrapper({Key? key, required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => MusicControlBloc(),
child: child,
);
}
}
/// your new implementation wherever you are declaring your details page
...
CollectionDetailsWrapper(
child: CollectionDetailsPage(...),
),
...
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论