我正在尝试制作一个可滑动以更改播放列表中当前正在播放的歌曲的小部件。我正在尝试通过让用户轻扫当前曲目和下一首曲目来模仿其他应用程序的操作方式。Dismissible非常接近我的实际需求。它具有很好的动画效果,我可以轻松地使用onDismissed函数来处理逻辑。我的问题是Dismissible实际上想要从树中删除小部件,这是我不想要的。
当歌曲改变时,我正在滑动的小部件会使用StreamBuilder进行更新,因此能够将小部件滑动到新的位置将是一个完美的选择。我可以这样做还是有更好的小部件可以满足我的需求?
这是我正在使用的小部件:
class NowPlayingBar extends StatelessWidget {
const NowPlayingBar({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return StreamBuilder<ScreenState>(
stream: _screenStateStream,
builder: (context, snapshot) {
if (snapshot.hasData) {
final screenState = snapshot.data;
final queue = screenState.queue;
final mediaItem = screenState.mediaItem;
final state = screenState.playbackState;
final processingState =
state?.processingState ?? AudioProcessingState.none;
final playing = state?.playing ?? false;
if (mediaItem != null) {
return Container(
width: MediaQuery.of(context).size.width,
child: Dismissible(
key: Key("NowPlayingBar"),
onDismissed: (direction) {
switch (direction) {
case DismissDirection.startToEnd:
AudioService.skipToNext();
break;
case DismissDirection.endToStart:
AudioService.skipToPrevious();
break;
default:
throw ("Unsupported swipe direction ${direction.toString()} on NowPlayingBar!");
}
},
child: ListTile(
leading: AlbumImage(itemId: mediaItem.id),
title: mediaItem == null ? null : Text(mediaItem.title),
subtitle: mediaItem == null ? null : Text(mediaItem.album),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (playing)
IconButton(
onPressed: () => AudioService.pause(),
icon: Icon(Icons.pause))
else
IconButton(
onPressed: () => AudioService.play(),
icon: Icon(Icons.play_arrow)),
],
),
),
),
);
} else {
return Container(
width: MediaQuery.of(context).size.width,
child: ListTile(
title: Text("Nothing playing..."),
));
}
} else {
return Container(
width: MediaQuery.of(context).size.width,
// The child below looks pretty stupid but it's actually genius.
// I wanted the NowPlayingBar to stay the same length when it doesn't have data
// but I didn't want to actually use a ListTile to tell the user that.
// I use a ListTile to create a box with the right height, and put whatever I want on top.
// I could just make a container with the length of a ListTile, but that value could change in the future.
child: Stack(
alignment: Alignment.center,
children: [
ListTile(),
Text(
"Nothing Playing...",
style: TextStyle(color: Colors.grey, fontSize: 18),
)
],
));
}
},
);
}
}
这就是我想要的效果(尽管我希望整个ListTile都可以被刷过,而不仅仅是歌曲名):https://i.imgur.com/ZapzpJS.mp4
答案 0 :(得分:0)
这可以通过使用confirmDismiss
回调而不是onDismiss
回调来完成。为了确保该窗口小部件不会真正被解散,您需要在函数末尾返回false。
Dismissible(
confirmDismiss: (direction) {
...
return false;
}
)