opt: 视频详情页appbar下滑动画

This commit is contained in:
guozhigq
2023-07-18 15:09:11 +08:00
parent 1cd9f951f9
commit 03f9420bec
2 changed files with 82 additions and 85 deletions

View File

@ -1,7 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:ui';
import 'package:extended_image/extended_image.dart';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart'; import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:flutter_meedu_media_kit/meedu_player.dart'; import 'package:flutter_meedu_media_kit/meedu_player.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@ -11,9 +9,10 @@ import 'package:pilipala/pages/video/detail/reply/index.dart';
import 'package:pilipala/pages/video/detail/controller.dart'; import 'package:pilipala/pages/video/detail/controller.dart';
import 'package:pilipala/pages/video/detail/introduction/index.dart'; import 'package:pilipala/pages/video/detail/introduction/index.dart';
import 'package:pilipala/pages/video/detail/related/index.dart'; import 'package:pilipala/pages/video/detail/related/index.dart';
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
import 'package:wakelock/wakelock.dart'; import 'package:wakelock/wakelock.dart';
import 'widgets/app_bar.dart';
class VideoDetailPage extends StatefulWidget { class VideoDetailPage extends StatefulWidget {
const VideoDetailPage({Key? key}) : super(key: key); const VideoDetailPage({Key? key}) : super(key: key);
@ -29,7 +28,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
Get.put(VideoDetailController(), tag: Get.arguments['heroTag']); Get.put(VideoDetailController(), tag: Get.arguments['heroTag']);
MeeduPlayerController? _meeduPlayerController; MeeduPlayerController? _meeduPlayerController;
final ScrollController _extendNestCtr = ScrollController(); final ScrollController _extendNestCtr = ScrollController();
late AnimationController animationController; late StreamController<double> appbarStream;
StreamSubscription? _playerEventSubs; StreamSubscription? _playerEventSubs;
bool isPlay = false; bool isPlay = false;
@ -62,19 +61,12 @@ class _VideoDetailPageState extends State<VideoDetailPage>
}, },
); );
animationController = AnimationController( appbarStream = StreamController<double>();
vsync: this, duration: const Duration(milliseconds: 600));
_extendNestCtr.addListener( _extendNestCtr.addListener(
() { () {
double offset = _extendNestCtr.position.pixels; double offset = _extendNestCtr.position.pixels;
if (offset > doubleOffset) { appbarStream.add(offset);
animationController.forward();
} else {
animationController.reverse();
}
doubleOffset = offset;
setState(() {});
}, },
); );
} }
@ -145,30 +137,6 @@ class _VideoDetailPageState extends State<VideoDetailPage>
bottom: false, bottom: false,
child: Stack( child: Stack(
children: [ children: [
Positioned(
top: 0,
left: 0,
right: 0,
child: Obx(
() => NetworkImgLayer(
type: 'emote',
src: videoDetailController.bgCover.value,
width: Get.size.width,
height: videoHeight,
),
),
),
Positioned.fill(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 100, sigmaY: 100), //可以看源码
child: Container(
decoration: BoxDecoration(
color:
Theme.of(context).colorScheme.background.withOpacity(0.1),
),
),
),
),
Scaffold( Scaffold(
resizeToAvoidBottomInset: false, resizeToAvoidBottomInset: false,
key: videoDetailController.scaffoldKey, key: videoDetailController.scaffoldKey,
@ -185,8 +153,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
scrolledUnderElevation: 0, scrolledUnderElevation: 0,
forceElevated: innerBoxIsScrolled, forceElevated: innerBoxIsScrolled,
expandedHeight: videoHeight, expandedHeight: videoHeight,
backgroundColor: Colors.transparent, // backgroundColor: Colors.transparent,
// backgroundColor: Theme.of(context).colorScheme.background, backgroundColor: Theme.of(context).colorScheme.background,
flexibleSpace: FlexibleSpaceBar( flexibleSpace: FlexibleSpaceBar(
background: Padding( background: Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
@ -320,52 +288,17 @@ class _VideoDetailPageState extends State<VideoDetailPage>
), ),
), ),
// 播放完成/暂停播放 // 播放完成/暂停播放
Positioned( StreamBuilder(
top: -statusBarHeight + stream: appbarStream.stream,
(doubleOffset / (videoHeight - kToolbarHeight)) * initialData: 0,
(kToolbarHeight - 9), builder: ((context, snapshot) {
left: 0, return ScrollAppBar(
right: 0, snapshot.data!.toDouble(),
child: Opacity( continuePlay,
opacity: doubleOffset / (videoHeight - kToolbarHeight), playerStatus,
child: Container( );
height: statusBarHeight + kToolbarHeight, }),
color: Theme.of(context).colorScheme.background, )
padding: EdgeInsets.only(top: statusBarHeight),
child: AppBar(
primary: false,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
title: TextButton(
onPressed: () => continuePlay(),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.play_arrow_rounded),
Text(
playerStatus == PlayerStatus.paused
? '继续播放'
: playerStatus == PlayerStatus.completed
? '重新播放'
: '播放中',
)
],
),
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(
Icons.share,
size: 20,
)),
const SizedBox(width: 12)
],
),
),
),
),
], ],
), ),
); );

View File

@ -0,0 +1,64 @@
import 'package:flutter/material.dart';
import 'package:flutter_meedu_media_kit/meedu_player.dart';
class ScrollAppBar extends StatelessWidget {
final double scrollVal;
Function callback;
final PlayerStatus playerStatus;
ScrollAppBar(
this.scrollVal,
this.callback,
this.playerStatus,
);
@override
Widget build(BuildContext context) {
final double statusBarHeight = MediaQuery.of(context).padding.top;
final videoHeight = MediaQuery.of(context).size.width * 9 / 16;
return Positioned(
top: -videoHeight + scrollVal + kToolbarHeight + 0.5,
left: 0,
right: 0,
child: Opacity(
opacity: scrollVal / (videoHeight - kToolbarHeight),
child: Container(
height: statusBarHeight + kToolbarHeight,
color: Theme.of(context).colorScheme.background,
padding: EdgeInsets.only(top: statusBarHeight),
child: AppBar(
primary: false,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
title: TextButton(
onPressed: () => callback(),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.play_arrow_rounded),
Text(
playerStatus == PlayerStatus.paused
? '继续播放'
: playerStatus == PlayerStatus.completed
? '重新播放'
: '播放中',
)
],
),
),
actions: [
IconButton(
onPressed: () {},
icon: const Icon(
Icons.share,
size: 20,
)),
const SizedBox(width: 12)
],
),
),
),
);
}
}