《flutter整活系列》开发个能看电影电视剧的app

最近有空关注了下flutter空安全升级,我也跟着升级了下,重构一下自己写的dart-cms-flutter项目。主要使用flutter + getx, 《getx yyds》

我不会放出采集那些数据,自己处理就好。这里只是说下如何做的
项目地址:Dart-Cms-Flutter
项目截图 《flutter整活系列》开发个能看电影电视剧的app
文章图片


从首页开始 由于使用了getx,所以,首页的部分需要改一些东西,这里需要多提一嘴的是,getx提供了全局注入控制器,相当于全局状态,非常好用,使用GetxService,下面是例子
这是一个收藏记录的例子,
import 'package:get/get.dart'; import 'package:dart_cms_flutter/utils/storage.dart'; import 'package:dart_cms_flutter/interface/videoDetaill.dart'; // 全局响应数据 class StoreService extends GetxService { // 历史记录 RxList storeList = [].obs; Future init() async { List storeData = https://www.it610.com/article/List.from(StorageUtil().getJSON("store") ?? []); storeList.addAll(storeData); return this; }Future add( T obj, ) async { // 插入一条新的 String newKey = obj.Id!; // 检查是否存在 bool isExist = storeList.any((el) => el["Id"] == newKey); // 是否超出限制50个存储配额, 并且当前历史记录中没有这个视频 if (storeList.length >= 50 && !isExist) { storeList.removeLast(); } // 当前的id是否已经存在 if (isExist) { // 存在就删除,重新插入,变化位置,插入到最前 storeList.removeWhere((el) => el["Id"] == newKey); } // 当前视频的数据 formant Map curVideoMap = _formantVideoDetaill( obj, ); // 插入新的 storeList.insert(0, curVideoMap); // 存入 // ignore: invalid_use_of_protected_member return StorageUtil().setJSON('store', storeList.value); }Future removeKey(String keyName) async { storeList.removeWhere((element) => true); return StorageUtil().remove(keyName); }Map _formantVideoDetaill( T obj, ) { return { "Id": obj.Id, "videoTitle": obj.videoTitle, "director": obj.director, "poster": obj.performer, "videoImage": obj.videoImage, "video_type": obj.videoType!.name, "video_rate": obj.videoRate, "update_time": obj.updateTime, "language": obj.language, "sub_region": obj.subRegion, "rel_time": obj.relTime, "introduce": obj.introduce, "remind_tip": obj.remindTip, "popular": obj.popular, "allow_reply": obj.allowReply, "display": obj.display, "scource_sort": obj.scourceSort, }; } }

全局注入,使得控制器不会被回收,下面是注入时的例子
Future main() async { WidgetsFlutterBinding.ensureInitialized(); // debugPaintSizeEnabled = true; await initStore(); runApp(MyApp()); }Future initStore() async { // 初始化http请求 HttpUtils().init(baseUrl: hostUrl); // 初始化单例模式 await StorageUtil().init(); // 这里注入历史记录模块 await Get.putAsync(() => HistoryService().init()); // 这里注入收藏记录模块 await Get.putAsync(() => StoreService().init()); print("全局注入"); }class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return ScreenUtilInit( // designSize: Size(375, 812), builder: () => GetMaterialApp( debugShowCheckedModeBanner: false, initialRoute: PageName.HOME, getPages: PageRoutes.routes, ), ); } }

在runapp之前注入这些需要的依赖,以及单例对象,
首页,文章页,分类页,页面部分 页面主要还是statefullwdiget, 但是getx给我们提供了一个简便操作,那就是getview,使用getview我们一些一次性请求的页面(指的是数据出现之后不会有下拉刷新这种情况下)使用getview就很方便,比如我上面的文章页面,下面是例子:
// view部分 class AppBarIndexView extends GetView{@override Widget build(BuildContext context) { // 这里注入控制器 AppbarIndexViewStore controller = Get.put(AppbarIndexViewStore()); return controller.obx( // 这里是成功时候展现的内容 (state) => Widget, // 这里是loading时候的内容 onLoading: widget, // 这里是为空数据时候的内容 onEmpty: widget, // 这里是失败时候的内 onError: widget, ) } }// 控制器部分 class AppbarIndexViewStore extends GetxController with SingleGetTickerProviderMixin,StateMixin {initEvent(){ // 改变状态,调用change方法 change("失败", status: RxStatus.error()); change("成功", status: RxStatus.success()); change("加载中", status: RxStatus.loading()); }@override void onInit() { super.onInit(); // 初始化控制要运行啥 initEvent(); } }

关键部分,视频播放器 【《flutter整活系列》开发个能看电影电视剧的app】flutter的视频播放器,我发过一篇水贴,各位可以看下,flutter这边目前你能够找到的播放器,比如chewie,betterplayer,这些都没有滑动快进上下滑动改变音量和屏幕亮度。所以对于你想开箱即用,还能满足一下下自己,很难。据我观察许久。如果你和我一样是一个垃圾小前端(大废物)。那么你最好是基于fijkplayer。
说到fijkplayer,必须得提一嘴,我基于fijkplayer开发的皮肤,在fijkplayer作者皮肤的基础之上开发的,加入了手势上下滑动改变音量和屏幕亮度,左右滑动快进快退。项目地址:fijkplayer_skin
效果就是上面截图的效果
这里着重说下给播放皮肤加功能,
快进快退实现
快进快退,说白了就是检测滑动的时候判断当前点和屏幕按下时候的点的距离,最简单的方法就是>大于就+1,小于就-1,以下是我的实现。这里只是函数部分,ui部分,你需要自己写布局,不想写可以抄袭下我的皮肤
_onHorizontalDragStart(detills) { setState(() { // 在按下的时候现存一下当前的点的位置 updatePrevDx = detills.globalPosition.dx; updatePosX = _currentPos.inSeconds; }); }_onHorizontalDragUpdate(detills) { double curDragDx = detills.globalPosition.dx; // 确定当前是前进或者后退 int cdx = curDragDx.toInt(); int pdx = updatePrevDx!.toInt(); bool isBefore = cdx > pdx; // + -, 不满足, 左右滑动合法滑动值,> 1 if (isBefore && cdx - pdx < 1 || !isBefore && pdx - cdx < 1) return null; int dragRange = isBefore ? updatePosX! + 1 : updatePosX! - 1; // 是否溢出 最大 int lastSecond = _duration.inSeconds; if (dragRange >= _duration.inSeconds) { dragRange = lastSecond; } // 是否溢出 最小 if (dragRange <= 0) { dragRange = 0; } // this.setState(() { _isHorizontalMove = true; _hideStuff = false; _isTouch = true; // 更新下上一次存的滑动位置 updatePrevDx = curDragDx; // 更新时间 updatePosX = dragRange.toInt(); _dargPos = Duration(seconds: updatePosX!.toInt()); }); }// 在松手的时候,说明就不打架了,所以就各回各家,各找各妈 _onHorizontalDragEnd(detills) { // 这里就给播放器设置更新后的位置,就是时间 player.seekTo(_dargPos.inMilliseconds); this.setState(() { _isHorizontalMove = false; _isTouch = false; _hideStuff = true; _currentPos = _dargPos; }); }

上下滑动也是同理,稍作修改便可以完成。至此一些主要的点结束。

    推荐阅读