簡介
最近花了兩天時間研究使用Flutter開發一個抖音國際版. 個人感覺使用Flutter開發app快得不要不要的額. 兩天就基本可以開發個大概出來. 最主要是熱過載,太方便實時調整UI佈局了. 相應速度極快. 如下圖:
主要專案架構
詳細說明一下,開發主要在lib資料夾
- pubspec.yaml是配置外掛的位置,如http: ^0.12.0+4,類似依賴元件.
- common資料夾存放的是重寫的網路元件,以及圖示元件icons.dart
- config資料夾存放的api.dart,wei呼叫的api配置檔案
- models檔案存放的實體層
- screen資料夾存放的頁面view層
- tabs存放的底部切換資料夾層
- widgets存放的元件,包含視訊播放元件player.dart以及左右等描述元件
功能介紹
主要的依賴元件,請使用國內映象下載,切記切記!!!!
flutter:
sdk: flutter
flutter_svg: ^0.17.4
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.3
cached_network_image: ^2.2.0
json_annotation: ^3.0.1
font_awesome_flutter: ^8.8.1
http: ^0.12.0+4
provider: ^4.0.4
avatar_glow: any
getflutter: ^1.0.11
flutter_money_formatter: ^0.8.3
video_player: ^0.10.8+1
dio: ^3.0.9
dio_cookie_manager: ^1.0.0
包含字型檔案,主要為抖音自帶的字型檔案
import 'package:flutter/widgets.dart'; class DouyinIcons { DouyinIcons._(); static const _kFontFam = 'DouyinIcons'; static const IconData chat_bubble = const IconData(0xe808, fontFamily: _kFontFam); static const IconData create = const IconData(0xe809, fontFamily: _kFontFam); static const IconData heart = const IconData(0xe80a, fontFamily: _kFontFam); static const IconData home = const IconData(0xe80b, fontFamily: _kFontFam); static const IconData messages = const IconData(0xe80c, fontFamily: _kFontFam); static const IconData profile = const IconData(0xe80d, fontFamily: _kFontFam); static const IconData reply = const IconData(0xe80e, fontFamily: _kFontFam); static const IconData search = const IconData(0xe80f, fontFamily: _kFontFam); }
此次採用Flutter開發安卓、IOS等 app確實方便,主要為將tiktok的資料使用http下載下來.
import 'package:http/http.dart' as http; class RequestController { static String host = "https://www.tiktok.com/"; String url = host + "/share/item/list?secUid=&id=&type=5&count=30&minCursor=0&maxCursor=0&shareUid=&lang=en&_signature=pKb.ogAgEB9ImoSQahoqJKSm.rAAPox"; Future<String> getCookie() async { try { var response = await http.get(host + "/share/item/"); return response.headers["set-cookie"]; } catch (e) { return "error"; } }
Model層
主要為實體層,解析json後繫結資料以及傳遞資料
class Tiktok { int statueCode; Body body; Object errMsg; Tiktok({this.statueCode, this.body, this.errMsg}); Tiktok.fromJson(Map<String, dynamic> json) { statueCode = json['statusCode']; body = json['body'] != null ? new Body.fromJson(json['body']) : null; errMsg = json['errMsg']; } Map<String, dynamic> toJson() { final Map<String, dynamic> data = new Map<String, dynamic>(); data['statusCode'] = this.statueCode; if (this.body != null) { data['body'] = this.body.toJson(); } data['errMsg'] = this.errMsg; return data; } }
檢視層
另外螢幕層主要包含三個,homescreen,trendingscreen,以及顯示videoscreen
import 'package:flutter/material.dart'; import 'package:flutter_app/Screens/trendingScreen.dart'; import 'package:flutter_app/widgets/bottom_toolbar.dart'; class Home extends StatefulWidget { @override HomeState createState() => HomeState(); } class HomeState extends State<Home> { int currentIndex = 0; PageController pageController; @override Widget build(BuildContext context) { return Scaffold( body: PageView( controller: pageController, children: <Widget>[ Trending(), ], onPageChanged: (int index) { setState(() { currentIndex = index; }); }, ), bottomNavigationBar: bottomItems(currentIndex, pageController), ); } }
Tending層,主要包含讀取抖音的api,將api轉化成實體物件,繫結資料到videoscreen頁面
import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/cupertino.dart'; import 'package:getflutter/getflutter.dart'; import 'package:flutter_app/config/api.dart'; import 'package:flutter_app/models/Tiktok.dart'; import 'package:http/http.dart' as http; import 'package:flutter_app/Screens/videoScreen.dart'; class Trending extends StatefulWidget { _TrendingState createState() => _TrendingState(); } class _TrendingState extends State<Trending> { PageController pageController; BuildContext context; RequestController api = RequestController(); List<Widget> videos = []; getTrending() async { var cookies = await api.getCookie(); api.setCookie(cookies); try { var response = await http.get( api.url, headers: api.headers, ); Tiktok tiktok = Tiktok.fromJson(jsonDecode(response.body)); tiktok.body.itemListData.forEach( (item) { setState(() { videos.add(VideoItem(data: item)); }); }, ); } catch (ex) { SimpleDialog( title: Text('Hot videos list is empty'), ); print(ex); } } @override void initState() { super.initState(); getTrending(); } @override Widget build(BuildContext context) { context = context; return PageView( scrollDirection: Axis.vertical, controller: pageController, children: videos.length == 0 ? <Widget>[ Container( color: Colors.black, child: Center( child: GFLoader( type: GFLoaderType.circle, loaderColorOne: Colors.blueAccent, loaderColorTwo: Colors.white, loaderColorThree: Colors.pink, ), ), ) ] : videos, ); } }
VideoScreen主要為繫結資料. 展示抖音的視訊
import 'package:flutter/material.dart'; import 'package:flutter_app/models/Tiktok.dart'; import 'package:flutter_app/widgets/video_description.dart'; import 'package:flutter_app/widgets/actions_toolbar.dart'; import 'package:flutter_app/widgets/player.dart'; class VideoItem extends StatelessWidget { final ItemListData data; const VideoItem({@required this.data}); @override Widget build(BuildContext context) { return Scaffold( body: Stack( children: <Widget>[ DouyinVideoPlayer( url: data.itemInfos.video.urls[0], ), title(), VideoDescription( description: data.itemInfos.text, musicName: data.musicInfos.musicName, authorName: data.musicInfos.authorName, userName: data.authorInfos.uniqueId, ), ActionsToolbar( comments: data.itemInfos.commentCount.toString(), userImg: data.authorInfos.covers[0], favorite: data.itemInfos.diggCount, coverImg: data.musicInfos.covers[0], ), ], ), ); } Widget title() => Align( alignment: Alignment.topCenter, child: Padding( padding: EdgeInsets.symmetric(vertical: 28.0), child: Text( "Trending | For You", style: TextStyle(color: Colors.white, fontSize: 19.0), ), ), ); }
此次開發主要時間用在搭建Flutter環境上,切記使用國內映象,另外調式需要配合代理即可。
其他待完成的包含底部的導航頁面,打算花兩天時間把剩餘的完成.
各位感興趣的可以到我的github上點一下star. 留言可以教你們開發以及搭建dart環境. 地址:https://github.com/WangCharlie/douyin
感興趣的各位留言哈.