前言

这次对布局进行优化,主要包含了首页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 设置

crossAxisAlignment: CrossAxisAlignment.start,顶部的布局是左边一个clear图标按钮,右边一个帮助按钮,所以使用Row布局,并且设置Row的mainAxisAlignment: MainAxisAlignment.spaceBetween,这样就左右布局了,其他依次采用SizeBox占位,
中间则采用Center来展示文字控件,底部的登录部分因为包含标签 超链接,所有采用RichText比较合适,包含TextSpan即可.

全部代码如下:

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,谢谢!!!

第四篇-用Flutter手撸一个抖音国内版,看看有多炫的更多相关文章

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

    前言 继上一篇使用Flutter开发的抖音国际版 后再次撸一个国内版抖音,大部分功能已完成,主要是Flutter开发APP速度很爽,  先看下图 项目主要结构介绍 这次主要的改动在api.dart 及 ...

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

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

  3. 第五篇- 抖音的强大对手来了,用Flutter手撸一个抖音国际版,看看有多炫

    前言 由于中间几个月项目天天加班,导致没没时间更新,最近一段时间对前端进行了重构,加了很多页面,如登录.注册.关注.个人中心等,目前写这个纯属业余个人爱好,所以断断续续的继续在做...... 前端地址 ...

  4. Golang:手撸一个支持六种级别的日志库

    Golang标准日志库提供的日志输出方法有Print.Fatal.Panic等,没有常见的Debug.Info.Error等日志级别,用起来不太顺手.这篇文章就来手撸一个自己的日志库,可以记录不同级别 ...

  5. 使用Flutter开发的抖音国际版

    简介 最近花了两天时间研究使用Flutter开发一个抖音国际版. 先上图,个人感觉使用Flutter开发app快得不要不要的额.  两天就基本可以开发个大概出来.   最主要是热更新,太方便实时调整U ...

  6. 使用Java Socket手撸一个http服务器

    原文连接:使用Java Socket手撸一个http服务器 作为一个java后端,提供http服务可以说是基本技能之一了,但是你真的了解http协议么?你知道知道如何手撸一个http服务器么?tomc ...

  7. 【手撸一个ORM】MyOrm的使用说明

    [手撸一个ORM]第一步.约定和实体描述 [手撸一个ORM]第二步.封装实体描述和实体属性描述 [手撸一个ORM]第三步.SQL语句构造器和SqlParameter封装 [手撸一个ORM]第四步.Ex ...

  8. 通过 Netty、ZooKeeper 手撸一个 RPC 服务

    说明 项目链接 微服务框架都包括什么? 如何实现 RPC 远程调用? 开源 RPC 框架 限定语言 跨语言 RPC 框架 本地 Docker 搭建 ZooKeeper 下载镜像 启动容器 查看容器日志 ...

  9. C#基于Mongo的官方驱动手撸一个Super简易版MongoDB-ORM框架

    C#基于Mongo的官方驱动手撸一个简易版MongoDB-ORM框架 如题,在GitHub上找了一圈想找一个MongoDB的的ORM框架,未偿所愿,就去翻了翻官网(https://docs.mongo ...

随机推荐

  1. D - The Bakery CodeForces - 834D 线段树优化dp···

    D - The Bakery CodeForces - 834D 这个题目好难啊,我理解了好久,都没有怎么理解好, 这种线段树优化dp,感觉还是很难的. 直接说思路吧,说不清楚就看代码吧. 这个题目转 ...

  2. H - Food HDU - 4292 网络流

    题目   You, a part-time dining service worker in your college’s dining hall, are now confused with a n ...

  3. vue-双向响应数据底层原理分析

    总所周知,vue的一个大特色就是实现了双向数据响应,数据改变,视图中引用该数据的部分也会自动更新 一.双向数据绑定基本思路 “数据改变,视图中引用该数据的部分也会自动更新“,从这句话,我们可以分析出以 ...

  4. 【HBase】HBase与MapReduce集成——从HDFS的文件读取数据到HBase

    目录 需求 步骤 一.创建maven工程,导入jar包 二.开发MapReduce程序 三.结果 需求 将HDFS路径 /hbase/input/user.txt 文件的内容读取并写入到HBase 表 ...

  5. Linux内核驱动学习(三)字符型设备驱动之初体验

    Linux字符型设备驱动之初体验 文章目录 Linux字符型设备驱动之初体验 前言 框架 字符型设备 程序实现 cdev kobj owner file_operations dev_t 设备注册过程 ...

  6. springboot controller templates html

    首先声明: @Controller注解的类必须要在启动类的子集目录下,否则无法扫描 本文要求: 通过controller层跳转页面到html页面(本篇用到thymeleaf模板) 项目结构展示: 第一 ...

  7. 【hdu1030】“坐标表示法”

    http://acm.hdu.edu.cn/showproblem.php?pid=1030 算法:以顶点为原点,建立坐标系,一个数可以唯一对应一个三元组(x, y, z),从任意一个点出发走一步,刚 ...

  8. Java并发II

    Java并发 J.U.C图 一.线程的安全性 当多个线程访问某个类的时候,不管运行环境采用何种方式调度或者这些线程如何交替执行,并且在主调代码中不需要任何额外的同步或者协同,这个类都可以表现出正确的行 ...

  9. 题解 P4296 【[AHOI2007]密码箱】

    由题意有 \(x^2\equiv 1\;mod\;n\) 对题目的公式进行变形 \(x^2-1=k\times n\) \((x+1)(x-1)=k\times n\) 由唯一分解定理,我们构造\(a ...

  10. 「雕爷学编程」Arduino动手做(40)——旋转编码器模块

    37款传感器与模块的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器和模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的,这里 ...