第五篇- 抖音的强大对手来了,用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/
第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫的更多相关文章
- 第二篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽, 先看下图 项目主要结构介绍 这次主要的改动在api.dart 及 ...
- 第三篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 前一篇已经开发了大部分框架,包含视频上下滑动播放,这次将上次未完成的数据显示友好显示,以及底部音乐走马灯特效,另外优化了加载数据的bug,在dart语言里 & 会自动变成& 另 ...
- 第四篇-用Flutter手撸一个抖音国内版,看看有多炫
前言 这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabview两个页面,一个关注 ...
- 五分钟,手撸一个Spring容器!
大家好,我是老三,Spring是我们最常用的开源框架,经过多年发展,Spring已经发展成枝繁叶茂的大树,让我们难以窥其全貌. 这节,我们回归Spring的本质,五分钟手撸一个Spring容器,揭开S ...
- 【手撸一个ORM】第五步、Expression(表达式目录树)转换为Where子句
说明 在SQL中,查询.修改比较常用到WHERE子句,在这里根据使用场景不同,定义了两个类,一个用于查询,一个用于修改(插入)操作.原因是: 查询操作支持一级导航属性查询,如student.Schoo ...
- 第五篇 SQL Server安全架构和安全
本篇文章是SQL Server安全系列的第五篇,详细内容请参考原文. 架构本质上是一个数据库对象,其他对象的一个容器,在复杂的数据库中它能够很容易的管理各组对象.架构具有重要的安全功能.在这一篇你会学 ...
- 【译】第五篇 SQL Server安全架构和安全
本篇文章是SQL Server安全系列的第五篇,详细内容请参考原文. 架构本质上是一个数据库对象,其他对象的一个容器,在复杂的数据库中它能够很容易的管理各组对象.架构具有重要的安全功能.在这一篇你会学 ...
- 【Python五篇慢慢弹】快速上手学python
快速上手学python 作者:白宁超 2016年10月4日19:59:39 摘要:python语言俨然不算新技术,七八年前甚至更早已有很多人研习,只是没有现在流行罢了.之所以当下如此盛行,我想肯定是多 ...
- 【Python五篇慢慢弹(4)】模块异常谈python
模块异常谈python 作者:白宁超 2016年10月10日12:08:31 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给出的pythondo ...
随机推荐
- 计算机电子书 2018 BiliDrive 备份
下载方式 根据你的操作系统下载不同的 BiliDrive 二进制. 执行: bilidrive download <link> 链接 文档 链接 Webpack 中文指南.epub (40 ...
- Git起始操作之设置全局用户名和Email地址
引自:廖雪峰老师的Git教程 因为Git是分布式版本控制系统,所以,每个机器都必须自报家门:你的名字和Email地址.你也许会担心,如果有人故意冒充别人怎么办?这个不必担心,首先我们相信大家都是善良无 ...
- 有关 iOS 的开发证书、应用标识、设备标识、配置文件以及密钥 #DF
iOS开发过程中如果需要进行真机调试.发布需要注册申请很多证书, 以下是对iOS开发的常用证书和密钥等的逐一简单说明: 证书 iOS常用的证书包括开发证书和发布证书,无论是真机调试还是最终发布应用到A ...
- jqGrid 修改单元格值或者替换图片及其他
var rowIds = jQuery("#list1").jqGrid('getDataIDs'); for (var k = 0; k < ...
- Solution -「LOJ #6029」「雅礼集训 2017」市场
\(\mathcal{Description}\) Link. 维护序列 \(\lang a_n\rang\),支持 \(q\) 次如下操作: 区间加法: 区间下取整除法: 区间求最小值: 区 ...
- Solution -「CERC 2016」「洛谷 P3684」机棚障碍
\(\mathcal{Description}\) Link. 给一个 \(n\times n\) 的网格图,每个点是空格或障碍.\(q\) 次询问,每次给定两个坐标 \((r_1,c_1), ...
- Solution -「ZJOI 2019」「洛谷 P5326」开关
\(\mathcal{Description}\) Link. 有 \(n\) 个开关,初始时所有开关的状态为 \(0\).给定开关的目标状态 \(s_1,s_2,\cdots,s_n\).每 ...
- .NET官方封装的Win32API类库
大部分朋友在使用C#.NET调用Win32API时都不清楚API函数的声明,要么就是抄网上的代码,但是总会遇到各种各样奇奇怪怪难以解决的问题,打算自己封装又发现工作量实在太大. 其实完全没有必要自己动 ...
- ConcurrentHashMap (jdk1.7)源码学习
一.介绍 1.Segment(分段锁) 1.1 Segment 容器里有多把锁,每一把锁用于锁容器其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并 ...
- 如何强制关闭Win10自动更新
今天我向往常一样打开了电脑,在工作时突然感觉CPU风扇嗡嗡的响电脑开始变得极慢内存也开始上涨,我意识到不妙了,Windows10 又开始在后台给我搞事情了,由于我的电脑安装有开机还原功能,所以每次开机 ...