第三篇-用Flutter手撸一个抖音国内版,看看有多炫

前言

前一篇已经开发了大部分框架,包含视频上下滑动播放,这次将上次未完成的数据显示友好显示,以及底部音乐走马灯特效,另外优化了加载数据的bug,在dart语言里 & 会自动变成&  另外优化了代码逻辑.

本系列会持续更新,将各个模块及功能持续完善,地址:https://github.com/WangCharlie/douyin  欢迎各位fork 和star. 谢谢!

运行效果如下图:

 

修复Dart语言 URL显示错误.

经过反复则是,发现url 在tostring()方法执行后 会把原来的 &替换成&amp,  所以暂时只能这样替换了 url = url.replaceAll('&', '&')来修复问题了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
getVideos(BillboardData v) async {
  try {
    var url = v.link.split("/")[5];
    var response = await http.get(
      api.video + url + "&dytk",
      headers: api.headers,
    );
    VideoData videoData = VideoData.fromJson(jsonDecode(response.body));
    //获取无水印的视频地址
    api.getRedirects(videoData.itemList[0].video.playaddr.uri).then((url) => {
          url = url.replaceAll('&amp', '&'),
          if (url != '')
            {
              videos.add(VideoItem(
                data: videoData,
                videourl: url,
              )),
              //print(url),
            }
        });
  } catch (ex) {
    print(ex);
  }
}

  

对数据友好格式化显示

如下图显示数据通常超过1000 会显示1k,超过10000显示1m,这样更加友好显示数据.  主要使用了package:flutter_money_formatter 这个组件

 1,先引用 import 'package:flutter_money_formatter/flutter_money_formatter.dart';

 2,使用如下方法

1
2
3
4
5
FlutterMoneyFormatter fmf =
    FlutterMoneyFormatter(amount: double.parse(widget.favorite.toString()));
 
FlutterMoneyFormatter fmf2 =
    FlutterMoneyFormatter(amount: double.parse(widget.comments));

3,显示的方法如下

1
fmf.output.compactNonSymbol

 

完整的实现代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
return Align(
       alignment: Alignment.bottomRight,
       widthFactor: 100.0,
       child: Column(
         mainAxisAlignment: MainAxisAlignment.end,
         mainAxisSize: MainAxisSize.min,
         children: <Widget>[
           _getFollowAction(),
           _getSocialAction(
               icon: DouyinIcons.heart,
               title: '${fmf.output.compactNonSymbol}'),
           _getSocialAction(
               icon: DouyinIcons.chat_bubble,
               title: '${fmf2.output.compactNonSymbol}'),
           _getSocialAction(
               icon: DouyinIcons.reply, title: '分享', isShare: true),
           _getMusicPlayerAction()
         ],
       ));
 }

底部音乐名字走马灯特效

先引入 import 'package:marquee_widget/marquee_widget.dart';  

反复测试后发现,这里需要设置width,否则没有效果,切记.  并使用container包含起来

1
2
3
4
5
6
7
8
9
10
11
  Container(
    width: 150,
    child: Marquee(
      child: Text('${widget.musicName} - ${widget.authorName}'),
      direction: Axis.horizontal,
      textDirection: TextDirection.ltr,
      animationDuration: Duration(seconds: 1),
      directionMarguee: DirectionMarguee.oneDirection,
    ),
  ),
])

 

 

音乐图标旋转效果

 

这里主要模仿抖音的音乐按钮旋转起来的特效,目前还未实现的地方是哪个音乐字符飞出来消失 

改造后的代码如下,先使用  SingleTickerProviderStateMixin,当元素显示时才播放动画效果

1
2
3
4
5
6
7
8
class _ActionsToolbarState extends State<ActionsToolbar>
    with SingleTickerProviderStateMixin {
  static const double ActionWidgetSize = 60.0;
  static const double ActionIconSize = 35.0;
  static const double ShareActionIconSize = 25.0;
  static const double ProfileImageSize = 50.0;
  static const double PlusIconSize = 20.0;
  AnimationController animationController;

 

然后设置初始化状态,以及各种初始化参数。间隔 seconds: 5,并且在初始化状态下把animationController 创建出来,下面的方法使用得到

1
2
3
4
5
6
7
8
9
@override
void initState() {
  super.initState();
  animationController = new AnimationController(
    vsync: this,
    duration: new Duration(seconds: 5),
  );
  animationController.repeat();
}

 

这里是完整的播放图标改造后的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
Widget _getMusicPlayerAction() {
    return Container(
        margin: EdgeInsets.only(top: 10.0),
        width: ActionWidgetSize,
        height: ActionWidgetSize,
        child: Column(children: [
          Container(
            decoration: new BoxDecoration(
              borderRadius: BorderRadius.all(Radius.circular(25.0)),
              color: Colors.black54,
            ),
            padding: EdgeInsets.all(11.0),
            height: ProfileImageSize,
            width: ProfileImageSize,
            child: AnimatedBuilder(
              animation: animationController,
              child: Container(
                decoration: BoxDecoration(
                  shape: BoxShape.circle,
                  gradient: musicGradient,
                  //border: Border.all(color: Colors.black87, width: 11.0),
                  image: DecorationImage(
                    image: NetworkImage(widget.coverImg),
                    fit: BoxFit.cover,
                  ),
                ),
              ),
              builder: (BuildContext context, Widget _widget) {
                return Transform.rotate(
                  angle: animationController.value * 6.3,
                  child: _widget,
                );
              },
            ),
 
            // decoration: BoxDecoration(
            //   shape: BoxShape.circle,
            //   gradient: musicGradient,
            //   border: Border.all(color: Colors.black87, width: 11.0),
            //   image: DecorationImage(
            //     image: NetworkImage(widget.coverImg),
            //     fit: BoxFit.cover,
            //   ),
            // ),
          ),
        ]));
  }

 未完成的还有搜索界面,消息页面、关注,登录界面,后续会继续完善这些界面

结语

本博客会持续更新,将在业余时间将其他的功能完善。请持续关注本博客,代码地址:https://github.com/WangCharlie/douyin

欢迎各位点击star 和fork 代码. 

posted @   风清扬 No.1  阅读(2349)  评论(1编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示