admin管理员组文章数量:1125742
I'm working on building a highly immersive media experience in Flutter using a combination of GridView, PageView, and VideoPlayer. My goal is to provide seamless transitions between these views, complete with animations for overscroll-to-pop, interactive image zooming, and intuitive tap-to-hide controls for both navigation bars and video playback.
For simplicity, I'm using Provider. However, I'm encountering jank during certain animations, particularly when transitioning from a displaying thumbnail to playing a video in the same page of the PageView as well as jank in the OverscrollPop widget.
I've outlined the key parts of my code and project structure below. My github repo has my full project you can take a look and/or contribute to some solutions :)
Homepage
MediaProvider is wrapped over the entire app in main.dart
body: Consumer<MediaProvider>(
builder: (context, provider, child) {
final List<Media> media = provider.media;
return Scrollbar(
child: RefreshIndicator(
onRefresh: () async {},
child: GridViewBuilder(media: media),
),
);
}
)
GridViewBuilder
This is a GridView.builder widget intended to handle the navigation from GridView to PageView
... return GestureDetector(
onTap: () => Navigator.push(
context, PageRouteBuilder(
opaque: true,
pageBuilder: (context, animation, secondaryAnim) {
mediaList: media,
initialPage: index,
}
transitionBuilder: (context, animation, secondaryAnim, child) {
return FadeTransition(
opacity: animation,
child: child,
);
})),
child: Hero(
tag: media[index].docId
child: Container(
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(media[index].thumbUrl)
fit: BoxFit.cover,
),
),
child: isVideo
? const Icon(Icons.play_arrow_rounded,
: const SizedBox.shrink(),
...
MediaPageviewProvider Provider Class
MediaPageviewProvider
is a temporary Provider class for the purpose of handling page controller, animation controller, transformation controller, DragToPopDirection, and TickerProvider
class MediaPageviewProvider extends ChangeNotifier {
MediaPageviewProvider({
required this.mediaList,
required this.dragToPopDirection,
required int initialPage,
required this.vysnc,
}) : pageController = PageController(initialPage: initialPage),
transformationController = TransformationController(),
animationController = AnimationController(
vsync: vsync,
duration: const Duration(milliseconds: 200),
),
currentIndex = initialPage {
transformationController.addListener(_onZoomChanged);
}
void toggleControls() {}
void pageChanged(int page) {}
void doubletapToZoom() {}
// isZoomed is used to ensure that the PageView and OverscrollPop are disabled if the
// image has been zoomed into
void _onZoomChanged() {
final scale = transformationController.value.getMaxScaleOnAxis();
isZoomed = scale > 1.0;
notifyListeners();
}
// For the optional video, initialize and set the videoPlayerController and
// notifylisteners
void initAndSetVideoPlayerController(String url) async {
// ValueListener
loadingVideo.value = true;
notifyListeners();
final controller = VideoPlayerControllerworkUrl(Uri.parse(url));
await controller.initialize();
videoController = controller;
loadingVideo.value = false;
notifyListeners();
}
void playPauseVideo() {}
...
PageviewPage
The bulk of the project exists here and i'll condense the code to make it easier to understand what's happening. Requires List<Media> mediaList
and int intialPage
.
// PageviewPageState Stateful Widget that extends SingleTickerProviderStsateMixin
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => MediaPageviewProvider(
mediaList: widget.mediaList,
dragToPopDirection: DragToPopDirection.vertical,
initialPage: widget.initialPage,
vsync: this,
),
child: Consumer<MediaPageviewProvider>(
builder: (context, provider, child) {
return Scaffold(
// extendBody and extendBodyBehindAppBar are attempts to help the InteractiveViewer
// playground
extendBody: true,
extendBodyBehindAppBar: true,
body: OverscrollPop(
enable: !provider.isZoomed,
dragToPopDirection: provider.dragToPopDirection,
child: GestureDetector(
onTap: provider.toggleControls,
onDoubleTap: provider.mediaList.length,
child: PageView.builder(
// assigned controller, itemCount, and onPageChanged,
physics: provider.isZoomed
? const NeverScrollableScrollPhysics()
: const ClampingScrollPhysics(),
itemBuilder: (context, index) {
return ContentItem(
media: provider.mediaList[index],
provider: provider,
);
},
),
),
),
);
}
),
);}
ContentItem
This widget will change state depending on MediaType {image, video}, and provider.videoController != null. Requires Media media
and MediaPageviewProvider provider
.
if (provider.videoController != null) {
return Stack(
children: [
AspectRatio(
aspectRatio: controller.value.aspectRatio,
child: VideoPlayer(controller),
),
Positioned(
bottom: 60 + kBottomNavigationBarHeight,
left: 10,
right: 10,
child: VideoControls(
// pass controller, provider.animationcontroller, and provider.showControls
),
),
],
);
}
VideoControls
A simple stack widget with two sliders (buffer and interactive), a play/pause button, volume button, and duration/video length timestamp. This widget utilizes the animationController and showControls boolean from the MediaPageviewProvider to hide or show video controls.
本文标签:
版权声明:本文标题:provider - how can i smooth transitions between GridView, PageView, and VideoPlayer in Flutter - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1736674189a1947089.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论