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

前言

这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabview两个页面,一个关注,一个推荐,左右切换,pageview被包含在tabview里面.

布局优化

抖音的顶部appbar 是悬浮层叠展示,而flutter的层叠组件是stack, 因此最外面采用stack, 其次中间是tabview,分别是关注和推荐两个选项卡,关注在没有登录的时候会弹出一个提示需要认证登录的页面,这里加了两个页面,subscriptionScreen.dart,另外一个是loginScreen.dart

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

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

@override

 Widget build(BuildContext context) {

   return Scaffold(

     //backgroundColor: Colors.transparent,

     body: Stack(

       //fit: StackFit.expand,

       children: [

         TabBarView(

           controller: _tabController,

           children: [

             Subscription(),

             PageView(

               allowImplicitScrolling: true,

               controller: _pageController,

               children: [

                 Trending(),

               ],

               onPageChanged: (int index) {

                 setState(() {

                   currentIndex = index;

                 });

               },

             ),

           ],

         ),

         Column(

           children: [

             AppBar(

               backgroundColor: Colors.transparent,

               elevation: 0,

               centerTitle: true,

               leading: IconButton(

                   icon: Icon(Icons.tv),

                   onPressed: () {

                     print('点击了直播按钮');

                   }),

               actions: [

                 //导航栏右侧菜单

                 IconButton(

                     icon: Icon(Icons.search),

                     onPressed: () {

                       print('点击了搜索按钮');

                     }),

               ],

               title: TabBar(

                 indicator: UnderlineTabIndicator(

                     borderSide: BorderSide(width: 2.0, color: Colors.white),

                     insets: EdgeInsets.symmetric(horizontal: 18.0)),

                 labelStyle: TextStyle(fontSize: 18),

                 isScrollable: true,

                 controller: _tabController,

                 tabs: toptabs,

                 onTap: (index) {

                   print(index);

                 },

               ),

             )

           ],

         ),

       ],

     ),

     bottomNavigationBar: bottomItems(),

   );

 }

  

底部弹出提示认证页面

在 onTap 方法里

1

2

3

Scaffold.of(context).showBottomSheet((BuildContext context) {

          return Login();

        });

BottomSheet 是一个底部滑出的组件

第四篇-用Flutter手撸一个抖音国内版,看看有多炫_第1张图片

1

2

3

4

5

6

new BottomSheet(

    onClosing: () {},

    builder: (BuildContext context) {

        return new Text('aaa');

    },

),

通常很少直接使用 BottomSheet 而是使用 showModalBottomSheet。直接时候的时候看到的知识 builder 里的内容。

1

2

3

4

Future showModalBottomSheet ({

    @required BuildContext context,

    @required WidgetBuilder builder

});

看一个示例

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

new MaterialButton(

    color: Colors.blue,

    child: new Text('点我'),

    onPressed: () {

        showModalBottomSheet(

            context: context,

            builder: (BuildContext context) {

                return new Container(

                    height: 300.0,

                    child: new Image.network(this.imgurl),

                );

            },

        ).then((val) {

            print(val);

        });

 

 具体详细介绍参考官网.

 

 

关注页面

第四篇-用Flutter手撸一个抖音国内版,看看有多炫_第2张图片

 

 整个页面布局,左右都有边距,顶部也有边距,所有采用Container包含,边距使用padding: EdgeInsets.only(top: 150.0, left: 65.0, right: 65.0),  背景颜色 color: Color.fromRGBO(14, 15, 26, 1),依次image,另外使用sizebox占用空间,

其他的中间层都是居中,所以采用center都是居中,另外登录按钮是占满屏幕的,所以也采用SizeBox,并且把width:设置为double.infinity,这样就占满屏幕,button采用默认的RaisedButton,在button的onpressed事件调用showBottomSheet

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

48

49

50

51

52

53

54

55

56

57

58

59

60

61

import 'package:flutter/material.dart';

import 'package:flutter_app/Screens/loginScreen.dart';

 

class Subscription extends StatefulWidget {

  @override

  State createState() => _SubscriptionState();

}

 

class _SubscriptionState extends State

    with TickerProviderStateMixin {

  final GlobalKey scaffoldKey = GlobalKey();

  @override

  Widget build(BuildContext context) {

    return Container(

      padding: EdgeInsets.only(top: 150.0, left: 65.0, right: 65.0),

      color: Color.fromRGBO(14, 15, 26, 1),

      child: Column(

          crossAxisAlignment: CrossAxisAlignment.start,

          children: [

            Image(image: AssetImage("assets/images/int_1581491273221.png")),

            SizedBox(height: 20),

            Center(

              child: Text(

                '你还没有登录',

                style: TextStyle(

                    color: Colors.white,

                    fontSize: 20.0,

                    fontWeight: FontWeight.w400),

              ),

            ),

            SizedBox(height: 10),

            Center(

              child: Text(

                '登录账号,查看你关注的精彩内容',

                style: TextStyle(

                    color: Color.fromRGBO(253, 253, 253, 0.6),

                    fontSize: 14.0,

                    fontWeight: FontWeight.w400),

              ),

            ),

            SizedBox(height: 20),

            SizedBox(

              width: double.infinity,

              child: RaisedButton(

                color: Color.fromRGBO(252, 1, 86, 1),

                child: Text(

                  '登录',

                  style: TextStyle(color: Colors.white),

                ),

                onPressed: () {

                  Scaffold.of(context)

                      .showBottomSheet((BuildContext context) {

                    return Login();

                  });

                },

              ),

            ),

          ]),

    );

  }

}

 

登录页面

布局如下图:

第四篇-用Flutter手撸一个抖音国内版,看看有多炫_第3张图片

 

 

这个页面整体布局顶部,左右都有边距,因此使用Container比较合适,设置背景颜色为color: Colors.white, 边距设置为padding:EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0, bottom: 50.0),整体布局采用Column,因为是上下布局,因此Column 设置

crossAxisAlignment: CrossAxisAlignment.start,顶部的布局是左边一个clear图标按钮,右边一个帮助按钮,所以使用Row布局,并且设置Row的mainAxisAlignment: MainAxisAlignment.spaceBetween,这样就左右布局了,其他依次采用SizeBox占位,

中间则采用Center来展示文字控件,底部的登录部分因为包含标签 超链接,所有采用RichText比较合适,包含TextSpan即可.

全部代码如下:

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

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

import 'package:flutter/gestures.dart';

import 'package:flutter/material.dart';

import 'package:url_launcher/url_launcher.dart';

 

class Login extends StatefulWidget {

  @override

  State createState() => _LoginState();

}

 

class _LoginState extends State {

  TapGestureRecognizer _myTapGestureRecognizer;

  @override

  void initState() {

    super.initState();

    _myTapGestureRecognizer = TapGestureRecognizer()

      ..onTap = () {

        launch('https://open.douyin.com/platform');

      };

  }

 

  @override

  void dispose() {

    _myTapGestureRecognizer.dispose();

    super.dispose();

  }

 

  @override

  Widget build(BuildContext context) {

    return Container(

      color: Colors.white,

      padding:

          EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0, bottom: 50.0),

      child: Column(

        crossAxisAlignment: CrossAxisAlignment.start,

        children: [

          Row(

            mainAxisAlignment: MainAxisAlignment.spaceBetween,

            children: [

              IconButton(

                icon: Icon(Icons.clear),

                onPressed: () {

                  Navigator.pop(context);

                },

                color: Colors.black,

              ),

              Text('帮助', style: TextStyle(color: Colors.black)),

            ],

          ),

          SizedBox(

            height: 150.0,

          ),

          Center(

            child: Text('180****2520',

                style: TextStyle(color: Colors.black, fontSize: 38)),

          ),

          Center(

            child: Text('认证服务由中国电信提供',

                style: TextStyle(

                    color: Color.fromRGBO(53, 53, 53, 1), fontSize: 12)),

          ),

          SizedBox(

            height: 50.0,

          ),

          SizedBox(

            width: double.infinity,

            child: RaisedButton(

              color: Color.fromRGBO(252, 1, 86, 1),

              child: Text(

                '本机号码一键登录',

                style: TextStyle(color: Colors.white),

              ),

              onPressed: () {

                showBottomSheet(

                    context: context, builder: (context) => Login());

              },

            ),

          ),

          SizedBox(

            height: 2.0,

          ),

          SizedBox(

            width: double.infinity,

            child: OutlineButton(

              color: Color.fromRGBO(252, 1, 86, 1),

              child: Text(

                '其他手机号码登录',

                style: TextStyle(color: Colors.black),

              ),

              onPressed: () {

                showBottomSheet(

                    context: context, builder: (context) => Login());

              },

            ),

          ),

          SizedBox(

            height: 5.0,

          ),

          Center(

              child: RichText(

            text: TextSpan(

              children: [

                TextSpan(

                  text: '登录即表明同意',

                  style: TextStyle(color: Color.fromRGBO(53, 53, 53, 0.8)),

                ),

                TextSpan(text: '  '),

                TextSpan(

                  text: '用户协议',

                  style: TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8)),

                ),

                TextSpan(text: '  '),

                TextSpan(

                  text: '和',

                  style: TextStyle(color: Color.fromRGBO(53, 53, 53, 0.8)),

                ),

                TextSpan(text: '  '),

                TextSpan(

                  text: '隐私政策',

                  style: TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8)),

                ),

              ],

            ),

          )),

          Center(

              child: RichText(

            text: TextSpan(

              children: [

                TextSpan(

                  text: '以及',

                  style: TextStyle(color: Color.fromRGBO(53, 53, 53, 0.8)),

                ),

                TextSpan(text: '  '),

                TextSpan(

                    text: '《中国电信认证服务条款》',

                    style: TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8)),

                    recognizer: _myTapGestureRecognizer),

              ],

            ),

          )),

          Expanded(

              flex: 1,

              child: Center(

                  heightFactor: 25.0,

                  child: Text('其他方式登录',

                      style:

                          TextStyle(color: Color.fromRGBO(0, 164, 219, 0.8))))),

        ],

      ),

    );

  }

}

变更记录

本次变更主要体现在首页的选项卡设计,需要层叠展示,并且透明的采用appbar显示出顶部的关注、推荐按钮,另外新增了关注页,登录页,并且把底部按钮以及右边的按钮都加上了触发时间

 

接下来要完成的双击心形按钮点赞,评论页面,分享页面,这些都可以采用showmodalbottomsheet方法打开一个底部抽屉页面

 

还有底部的首页刷新,消息页面,拍短视频页面,消息页面,我的个人信息页面

 

结语

请继续关注本博客,其他页面持续更新完成,源码地址:https://github.com/WangCharlie/douyin,欢迎fork和star,谢谢!!!

你可能感兴趣的:(手机开发,Dart,Flutter)