來看看使用Flutter開發(fā)的抖音國際版~

簡介

最近花了兩天時間研究使用Flutter開發(fā)一個抖音國際版. 個人感覺使用Flutter開發(fā)app快得不要不要的額. 兩天就基本可以開發(fā)個大概出來. 最主要是熱重載,太方便實時調(diào)整UI布局了. 相應(yīng)速度極快. 如下圖:


122099-20200521004019059-1032545443.gif

主要項目架構(gòu)

image.png

詳細(xì)說明一下,開發(fā)主要在lib文件夾

  • pubspec.yaml是配置插件的位置,如http: ^0.12.0+4,類似依賴組件.
  • common文件夾存放的是重寫的網(wǎng)絡(luò)組件,以及圖標(biāo)組件icons.dart
  • config文件夾存放的api.dart,wei調(diào)用的api配置文件
  • models文件存放的實體層
  • screen文件夾存放的頁面view層
  • tabs存放的底部切換文件夾層
  • widgets存放的組件,包含視頻播放組件player.dart以及左右等描述組件

功能介紹

主要的依賴組件,請使用國內(nèi)鏡像下載,切記切記?。。?!

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開發(fā)安卓、iOS等 app確實方便,主要為將tiktok的數(shù)據(jù)使用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后綁定數(shù)據(jù)以及傳遞數(shù)據(jù)

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轉(zhuǎn)化成實體對象,綁定數(shù)據(jù)到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主要為綁定數(shù)據(jù). 展示抖音的視頻

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),
          ),
        ),
      );
}

此次開發(fā)主要時間用在搭建Flutter環(huán)境上,切記使用國內(nèi)鏡像,另外調(diào)式需要配合代理即可。

其他待完成的包含底部的導(dǎo)航頁面,打算花兩天時間把剩余的完成.


image.png

出處:原文地址

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容