Recently I had some time to pay attention to the upgrade of flutter air safety. I also updated my darT-CMS-Flutter project. Mainly use Flutter + getx, GetX YYds
I’m not gonna release that data. I’m just gonna do it myself. I’m just saying how do you do it
Project address: DarT-CMS -Flutter
Project screenshots
Start with the home page
Getx provides a global injection controller, which is equivalent to global state, which is very useful. Use GetxService. Here’s an example
This is an example of a collectible record,
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<dynamic> storeList = []. Future<StoreService> init() async { List<Map<String, dynamic>> storeData = List.from(StorageUtil().getJSON("store") ?? []); storeList.addAll(storeData); return this; } Future<bool> add<T extends VideoDetaillInterFace>(T obj,) async {// Insert a new String newKey = obj.id! ; // Check whether bool isExist = storelist. any((el) => el["Id"] == newKey); If (storelist.length >= 50 &&! isExist) { storeList.removeLast(); } // If (isExist) {// If (isExist) {// If (isExist) {// If (isExist) {// If (isExist) {// If (isExist) {// Storelist.removeWHERE ((el) => el[" id "] == newKey); Formant Map<String, dynamic> curVideoMap = _formantVideoDetaill(obj,); // Insert new storelist. insert(0, curVideoMap); // Ignore: invalid_use_of_protected_member return StorageUtil().setjson ('store', storelist.value); } Future<bool> removeKey(String keyName) async { storeList.removeWhere((element) => true); return StorageUtil().remove(keyName); } Map<String, dynamic> _formantVideoDetaill<T extends VideoDetaillInterFace>( 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, }; }}Copy the code
Global injection, so that the controller is not recycled, the following is an example of injection
Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); // debugPaintSizeEnabled = true; await initStore(); runApp(MyApp()); } Future<void> initStore() async {// Initialize HTTP request HttpUtils().init(baseUrl: hostUrl); // Initialize the singleton pattern await StorageUtil().init(); // Inject the history module await get.putasync (() => HistoryService().init()); PutAsync (() => StoreService().init())); Print (" global injection "); } 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, ), ); }}Copy the code
Injecting these required dependencies, as well as singletons, before RunApp,
Home page, article page, category page, page section
The page is still mostly stateFullwDiget, but getX provides us with a simple operation called getView, which is very convenient for some of our one-time request pages (meaning there is no drop-down refresh after data appears). Here’s an example of my article page above:
AppBarIndexView extends GetView<AppbarIndexViewStore>{@override Widget build(BuildContext context) {// AppbarIndexViewStore Controller = get.put (AppbarIndexViewStore()); Return controller.obx(// here is the content of the successful (state) => Widget, // here is the content of loading onLoading: OnEmpty: widget, // Here is the content for empty data, // here is the inner onError for failure: widget, Part)}} / / controller class AppbarIndexViewStore extends GetxController with SingleGetTickerProviderMixin, StateMixin { InitEvent (){// Change the state by calling the change method change(" failed ", status: rxstatus.error ()); Change (" success ", status: rxstatus.success ()); Change (" loading ", status: rxstatus.loading ()); } @override void onInit() { super.onInit(); // Init controls what initEvent() to run; }}Copy the code
The key part, video player
I posted a post about the video players for Flutter. You can take a look at the current players that you can find on flutter, such as Chewie and BetterPlayer. None of these have the ability to slide fast forward up and down to change the volume and brightness of the screen. So it’s hard to satisfy yourself a little bit out of the box. I’ve been watching for a long time. If you’re a little junk like me (big junk). Then you’d better use fijkPlayer.
Speaking of FijkPlayer, I have to mention that the skin THAT I developed based on FijkPlayer, based on the author skin of FijkPlayer, added gestures that swipe up and down to change volume and screen brightness, swipe left and right to fast forward and fast backward. Project address: fijkplayer_skin
The effect is the one shown in the screenshot above
I’m going to focus on adding features to play skins,
Fast forward fast rewind implementation
Fast forward and fast rewind, to put it plainly, is to judge the distance between the current point and the point when the screen is pressed down when detecting the slide. The simplest method is > > +1, less than -1. The following is my implementation. This is just the function part, the UI part, you need to write your own layout, if you don’t want to write, you can copy my skin
_onHorizontalDragStart (detills) {setState (() {/ / in the press the location of the current existing point 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; / / + -, not satisfied, and about sliding legal value, > 1 if (isBefore && CDX - symbol < 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; // Update time updatePosX = dragrange.toint (); _dargPos = Duration(seconds: updatePosX! .toInt()); }); } _onHorizontalDragEnd(detills) {// Set the player's position after the update. SeekTo (_dargpos.inmilliseconds); this.setState(() { _isHorizontalMove = false; _isTouch = false; _hideStuff = true; _currentPos = _dargPos; }); }Copy the code
The same goes for swiping up and down, which can be done with a few modifications. This concludes some of the major points.