第四篇-用Flutter手撸一个抖音国内版,看看有多炫
前言
这次对布局进行优化,主要包含了首页tabview pageview 以及添加几个按钮的操作过程.主要使用到stack层叠布局,tabpview和pageview,tabview两个页面,一个关注,一个推荐,左右切换,pageview被包含在tabview里面.
布局优化
抖音的顶部appbar 是悬浮层叠展示,而flutter的层叠组件是stack, 因此最外面采用stack, 其次中间是tabview,分别是关注和推荐两个选项卡,关注在没有登录的时候会弹出一个提示需要认证登录的页面,这里加了两个页面,subscriptionScreen.dart,另外一个是loginScreen.dart
@override Widget build(BuildContext context) { return Scaffold( //backgroundColor: Colors.transparent, body: Stack( //fit: StackFit.expand, children: <Widget>[ TabBarView( controller: _tabController, children: <Widget>[ Subscription(), PageView( allowImplicitScrolling: true, controller: _pageController, children: <Widget>[ 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: <Widget>[ //导航栏右侧菜单 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 方法里
Scaffold.of(context).showBottomSheet<void>((BuildContext context) { return Login(); });
BottomSheet 是一个底部滑出的组件
new BottomSheet( onClosing: () {}, builder: (BuildContext context) { return new Text('aaa'); }, ),
通常很少直接使用 BottomSheet 而是使用 showModalBottomSheet。直接时候的时候看到的知识 builder 里的内容。
Future<T> showModalBottomSheet <T>({ @required BuildContext context, @required WidgetBuilder builder });
看一个示例
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); });
具体详细介绍参考官网.
关注页面
整个页面布局,左右都有边距,顶部也有边距,所有采用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
import 'package:flutter/material.dart'; import 'package:flutter_app/Screens/loginScreen.dart'; class Subscription extends StatefulWidget { @override State<StatefulWidget> createState() => _SubscriptionState(); } class _SubscriptionState extends State<Subscription> with TickerProviderStateMixin { final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>(); @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: <Widget>[ 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<void>((BuildContext context) { return Login(); }); }, ), ), ]), ); } }
登录页面
布局如下图:
这个页面整体布局顶部,左右都有边距,因此使用Container比较合适,设置背景颜色为color: Colors.white, 边距设置为padding:EdgeInsets.only(top: 25.0, left: 25.0, right: 25.0, bottom: 50.0),整体布局采用Column,因为是上下布局,因此Column 设置
全部代码如下:
import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; class Login extends StatefulWidget { @override State<StatefulWidget> createState() => _LoginState(); } class _LoginState extends State<Login> { 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,谢谢!!!