第五篇-抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫

博客 分享
0 257
张三
张三 2022-03-10 13:56:26
悬赏:0 积分 收藏

第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫

前言

由于中间几个月项目天天加班,导致没没时间更新,最近一段时间对前端进行了重构,加了很多页面,如登录、注册、关注、个人中心等,目前写这个纯属业余个人爱好,所以断断续续的继续在做......

前端地址:https://www.pgyer.com/dtok
后端服务器地址:http://47.95.209.198:8181/

注释:由于本人的apple id无法打包ios、所以暂时只打包的android版本,ios版本正在解决账号问题

效果如下:

架构更新

之前技术采用flutter做的前端,后端api则对接的是抖音官方api,由于抖音的官方api更新频繁,导致经常播放不了,所以索性自己来写服务器后端api,那么后端api采用了那些技术咧

  • springcloud 主要是后台控制面板 演示地址:http://47.95.209.198:8181/login
  • elasticsearch 主要对视频数据离线查询
  • ipfs 用于分布式节点存储短视频
  • ethereum 用户激励用户存储短视频、毕竟买服务器存花费够大的

界面更新

  • 支持国家化,多语言切换
  • ipfs上传、下载文件
  • 登录页面
  • 注册页面
  • 上下轮播时优化播放效果
  • 点赞功能

其他功能还在继续完善,各位喜欢的话欢迎点个star 前端项目地址:https://github.com/telsacoin/telsavideo
后端需要的话请留下邮箱

本期最大的优化就是国际化,flutter国家化按以下步骤

在pubspec.yaml文件加上

  flutter:    sdk: flutter  flutter_localizations:    sdk: flutter  intl: ^0.17.0 # Add this line  ffi: ^1.1.2

在底部的flutter设置里添加

# The following section is specific to Flutter.flutter:  # The following line ensures that the Material Icons font is  # included with your application, so that you can use the icons in  # the material Icons class.  uses-material-design: true  generate: true # Add this line

新建多语言包

在lib目录新建子目录l10n
里面添加app_zh.arb文件
内容如下:

{    "home_top_foryou":"推荐",    "home_top_following":"关注",    "home_share":"分享",    "home_buttom_title":"首页",    "home_buttom_discover":"发现",    "home_buttom_notification":"通知",    "home_buttom_persion":"我"}

在main文件引用

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

在build里加入多语言检测及支持的代码

return MaterialApp(    debugShowCheckedModeBanner: false,    onGenerateTitle: (context) =>        AppLocalizations.of(context)!.home_buttom_title,    home: SplashScreen(),    localeResolutionCallback: (      Locale? locale,      Iterable<Locale> supportedLocales,    ) {      return locale;    },    localizationsDelegates: AppLocalizations.localizationsDelegates,    supportedLocales: AppLocalizations.supportedLocales,    theme: ThemeData(      textSelectionTheme: TextSelectionThemeData(        cursorColor: Colors.white,      ),      splashColor: Colors.transparent,      highlightColor: Colors.transparent,      primarySwatch: Colors.red,      primaryColor: Colors.black,      indicatorColor: Colors.white,      tabBarTheme: TabBarTheme(),    ),    /* initialRoute: '/',   onGenerateRoute: RouteGenerator.generateRoute, */    builder: (context, child) {      return ScrollConfiguration(        behavior: MyBehavior(),        child: child!,      );    },  );

然后在需要引用的位置加入

import 'package:flutter_gen/gen_l10n/app_localizations.dart';

调用的位置

AppLocalizations.of(context)!.home_top_foryou

至此,国际化就完成了

另外本地针对播放模块进行了优化,将代码拆分到videoplayer.dart文件.一来是方便代码阅读,而来可以作为子组件使用,其他的代码写得太冗余也在继续拆开,独立出来,各位感兴趣的可以关注项目的进展。

采用FutureBuilder对界面请求数据异步处理,当加载完成后才播放,效果更佳

代码如下:

return FutureBuilder<DTok>(    future: videos,    builder: (context, snapshot) {      print(snapshot.connectionState);      if (snapshot.connectionState == ConnectionState.waiting) {        return loading;        // return Column(        //   crossAxisAlignment: CrossAxisAlignment.center,        //   mainAxisAlignment: MainAxisAlignment.center,        //   children: [        //     loading,        //     Visibility(        //       visible: snapshot.hasData,        //       child: PageView.builder(        //           controller: foryouController,        //           onPageChanged: (index) {        //             //when the video is changing, release the previous video instance.        //             //disposeVideo();        //             setState(() {});        //           },        //           scrollDirection: Axis.vertical,        //           itemCount: snapshot.data!.itemList!.length,        //           itemBuilder: (context, index) {        //             var item = snapshot.data!.itemList![index];        //             return Videoplayer(        //               item: item,        //               width: MediaQuery.of(context).size.width,        //               heigth: MediaQuery.of(context).size.height,        //             );        //           }),        //     )        //   ],        // );      } else if (snapshot.connectionState == ConnectionState.done) {        if (snapshot.hasError) {          return Column(            crossAxisAlignment: CrossAxisAlignment.center,            mainAxisAlignment: MainAxisAlignment.center,            children: [              const Text('Error, Please restart your app agagin')            ],          );        } else if (snapshot.hasData) {          try {            return PageView.builder(                controller: foryouController,                onPageChanged: (index) {                  //when the video is changing, release the previous video instance.                  //disposeVideo();                  //setState(() {});                },                scrollDirection: Axis.vertical,                itemCount: snapshot.data!.itemList!.length,                itemBuilder: (context, index) {                  var item = snapshot.data!.itemList![index];                  return Videoplayer(                    item: item,                    width: MediaQuery.of(context).size.width,                    heigth: MediaQuery.of(context).size.height,                  );                });          } catch (e) {            return Container(              width: MediaQuery.of(context).size.width,              height: MediaQuery.of(context).size.height,              color: Colors.black,              child: Center(                  child: Text(                'Error, Please restart your app again.',                style: TextStyle(color: Colors.white),              )),            );          }        } else {          // empty data          return loading;        }      } else {        return Text('State: ${snapshot.connectionState}');      }    });

这里可以看到当snapshot.connectionState == ConnectionState.waiting的时候请求的数据正在加载中,则显示加载的图标loading

当snapshot.connectionState == ConnectionState.done 时,此时数据已经加载完毕,但是加载完毕有可能也没有数据,所以需要判断不同的情况

当加载出现异常情况则显示异常的widget

if (snapshot.hasError) {      return Column(        crossAxisAlignment: CrossAxisAlignment.center,        mainAxisAlignment: MainAxisAlignment.center,        children: [          const Text('Error, Please restart your app agagin')        ],      );    } 

当if (snapshot.hasData)则说明有返回值,但是这个返回值不一定就是我们需要的数据,所以还需要try catch一下,保证呈现给用户的界面是正常的

try {      return PageView.builder(          controller: foryouController,          onPageChanged: (index) {            //when the video is changing, release the previous video instance.            //disposeVideo();            //setState(() {});          },          scrollDirection: Axis.vertical,          itemCount: snapshot.data!.itemList!.length,          itemBuilder: (context, index) {            var item = snapshot.data!.itemList![index];            return Videoplayer(              item: item,              width: MediaQuery.of(context).size.width,              heigth: MediaQuery.of(context).size.height,            );          });    } catch (e) {      return Container(        width: MediaQuery.of(context).size.width,        height: MediaQuery.of(context).size.height,        color: Colors.black,        child: Center(            child: Text(          'Error, Please restart your app again.',          style: TextStyle(color: Colors.white),        )),      );    }  } 

其他情况则返回加载状态,因为没有数据返回

另外加载videoplay的时候把width、heigth传入到下一个控件,这样好计算界面呈现的宽度与高度

return Videoplayer(        item: item,        width: MediaQuery.of(context).size.width,        heigth: MediaQuery.of(context).size.height,      );

结语

请继续关注本博客,其他页面持续更新完成,源码地址:telsavideo, 欢迎fork和star,谢谢!!!

再次奉上演示地址:
前端地址:https://www.pgyer.com/dtok
后端服务器地址:http://47.95.209.198:8181/

posted @ 2022-03-10 13:08 风清扬 No.1 阅读(169) 评论(2) 编辑 收藏 举报
回帖
    张三

    张三 (王者 段位)

    821 积分 (2)粉丝 (41)源码

     

    温馨提示

    亦奇源码

    最新会员