使用Flutter开发的抖音国际版实例代码详解

简介

最近花了两天时间研究使用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

总结

到此这篇关于使用Flutter开发的抖音国际版的文章就介绍到这了,更多相关flutter抖音国际版内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • flutter InkWell实现水波纹点击效果

    在flutter 开发中用InkWell或者GestureDetector将某个组件包起来,已添加点击事件. GestureDetector 使用点击无水波纹出现,InkWell可以实现水波纹效果. 正常情况下使用 : InkWell( //单击事件响应 onTap: () { }, child: Container( alignment: Alignment(0, 0), height: 28, width: 120, child: Text("InkWell单击事件"), ), )

  • Flutter实现抖音点赞效果

    效果图如下: 分析效果 1.整个控件可以点击,控件可以铺满屏幕,点赞效果在子部件之上. 2.可以实现单击 3.连击的情况下,呈现红心的动画效果,并且有红心叠加 4.动画的位置会随着手指的点击位置改变 思路 1.通过GestureDetector来监控手势,在手指抬起的时候记录时间毫秒值,手指再次按下时,通过获取到毫秒值与之前的时间毫秒值的差值,来判断是单击还是呈现红心动画效果. 2.使用Stack部件来确定视图层级,比如说如果要在视频视图上实现点赞效果的话,视频视图部件就作为子部件,置于下层.

  • Flutter 超实用简单菜单弹出框 PopupMenuButton功能

    相信在实际开发过程当中,肯定少不了这样的功能: 点击 AppBar 右上角的按钮,弹出一个菜单供用户选择. 幸运的是,Flutter 提供给我们了一个 Widget,直接就能实现如上的效果. PopupMenuButton 还是老规矩,先看官方的说明: Displays a menu when pressed and calls onSelected [1] when the menu is dismissed because an item was selected. The value pa

  • Flutter持久化存储之数据库存储(sqflite)详解

    前言 数据库存储是我们常用的存储方式之一,对大批量数据有增.删.改.查操作需求时,我们就会想到使用数据库,Flutter中提供了一个sqflite插件供我们用于大量数据执行CRUD操作.本篇我们就来一起学习sqflite的使用. sqflite是一款轻量级的关系型数据库,类似SQLite. 在Flutter平台我们使用sqflite库来同时支持Android 和iOS. sqflite使用 引入插件 在pubspec.yaml文件中添加path_provider插件,最新版本为1.0.0,如下:

  • flutter日期选择器 flutter时间选择器

    本文实例为大家分享了flutter日期时间选择器的具体代码,供大家参考,具体内容如下 1 日期选择器 //设置默认显示的日期为当前 DateTime initialDate = DateTime.now(); void showDefaultYearPicker(BuildContext context) async { final DateTime dateTime = await showDatePicker( context: context, //定义控件打开时默认选择日期 initia

  • 详解flutter之网络请求dio,请求,拦截器简单示例

    flutter一直很火的网络请求插件dio 直接上代码,写成一个类,可以直接使用 包含请求的封装,拦截器的封装 import 'package:dio/dio.dart'; import 'dart:async'; import 'dart:io'; import './apidomain.dart'; import './httpHeaders.dart'; import 'package:shared_preferences/shared_preferences.dart'; class D

  • 详解Flutter WebView与JS互相调用简易指南

    本文采用Flutter官方WebView插件:https://pub.dartlang.org/packages/webview_flutter WebView与JS互相调用是一个刚需,但是貌似现在大家写的文章讲的都不是很清楚,我这个简易指南简单粗暴地分为两部分:JS调用Flutter和Flutter调用JS,拒绝花里胡哨,保证一看就懂,一学就会. 开始之前先简单了解一下官方WebView所包含的API: onWebViewCreated:在WebView创建完成后调用,只会被调用一次: ini

  • Flutter进阶之实现动画效果(一)

    上一篇文章我们了解了Flutter的动画基础,这一篇文章我们就来实现一个图表的动画效果. 首先,我们需要创建一个新项目myapp,然后把main.dart的内容替换成下面的代码 import 'package:flutter/material.dart'; import 'dart:math'; void main() { runApp(new MyApp()); } class MyApp extends StatelessWidget { @override Widget build(Bui

  • Flutter中如何加载并预览本地的html文件的方法

    直接进入主题,大概步骤如下 在 assets 创建需要访问 html 文件,如下 这里创建一个files文件夹,专门来放这些静态 html 文件. 在 pubspec.yaml 中配置访问位置 assets: - assets/images/ - assets/files/ 在 pubspec.yaml 添加 webview_flutter 插件依赖 webview_flutter: ^0.3.15+1 // 具体版本请查看官网 进入实际的代码操作 import 'dart:convert';

  • Flutter启动页(闪屏页)的具体实现及原理详析

    为什么要有启动页? 在以下文章中,启动页就是闪屏页. 现在大部分App都有启动页,那么为什么要有启动页?这是个值得思考的问题,如果没有启动页会怎样,大部分的App会白屏(也有可能是黑屏,主题设置有关系)非常短的时间,然后才能展示App的内容. 那么问题来了,一定要有启动页吗?答案:不是,而且是尽可能不要有启动页,因为启动页会让用户体验不够连贯,甚至IOS在开发手册上就不推荐使用启动页. 我们深入思考一下,既然不推荐为什么这样流行,答案非常简单,启动页的成本非常低,如果你想把的App启动优化到一个

随机推荐