Flutter仿照airbnb创建app
github地址:https://github.com/GainLoss/flutter-app
一、基础
flutter是谷歌公司开发的开源免费的UI框架,用dart语言实现的,可以实现跨平台,一套代码可以在Android Ios Windows Max Linux系统运行;使用120fps,基于GPU渲染;
1.Widget
在flutter中一切都是Widget(和react里面一切都是组件好像),文字 图片 甚至路由都是Widget;
flutter的底层架构(在flutter官网上有)
1.主题风格:
我们的主题风格可以分为Material和Cupertino是两种风格的主题包(前者是android后者是ios),风格是可以选择的,你也可以直接用基础的组件也是可以的;
基础组件:https://flutterchina.club/widgets/
Material:https://flutterchina.club/widgets/material/
Cupertino:https://flutterchina.club/widgets/cupertino/
Text 文本
Text( '文本', style:TextStyle(fontSize:10.0,color:Colors.red,fontWeight:FontWeight[500],fontFamily:'字体类型'),//文本类型颜色之类的 textAlign:TextAlign.center,//文本居中 maxLines:2,//最多显示几行 textDirection:TextDirection.rtl,//文本方向 overflow:TextOverflow.ellipsis,//用省略号结尾 softWrap:false,//是否自动换行 textScaleFactor:20.0,//字体显示倍率 locale//区域设置 )
Image 图片
方法 | 释义 |
---|---|
Image() | 从ImageProvider中获取图片,从本质上看,下面的几个方法都是他的具体实现。 |
Image.asset(String name) | 从AssetBundler中获取图片 |
Image.network(String src) | 显示网络图片 |
Image.file(File file) | 从File中获取图片 |
Image.memory(Uint8List bytes) | 从Uint8List中显示图片 |
可以有这几种获取图片的方法,那么里面数据主要有哪几个呢
Image( width:10.0, height:10.0, color: Colors.greenAccent, colorBlendMode: BlendMode.colorBurn,//和color混合使 alignment: Alignment.center, //居中 repeat: ImageRepeat.noRepeat//重复 )
Icon 图标 官方图标:https://material.io/tools/icons/?icon=favorite_border&style=baseline
Icon( Icons.ac_unit, color:Colors.red, size:10.0, )
TextField 输入框
TextField( TextEditingController controller, //控制正在编辑的文本 FocusNode focusNode, //是否具有键盘焦点 InputDecoration decoration: const InputDecoration(), //样式 TextInputType keyboardType,//键盘类型 TextInputAction textInputAction, //控制键盘的功能键 指enter键,比如此处设置为next时,enter键 显示的文字内容为 下一步 TextStyle style, //文字样式 TextAlign textAlign: TextAlign.start, //文字位置 TextDirection textDirection, //文字下划线 bool autofocus: false, //是否自动获取焦点 bool obscureText: false, //隐藏文本输入内容 用 圆点 符号代替 bool autocorrect: true, //是否自动更正 int maxLines: 1,//显示行数 int maxLength, //限制长度 bool maxLengthEnforced: true, //如果这个为false那么maxLength设置了也没有用 onChanged:(){},//改变事件 onEditingComplete,//编辑完成事件 onSubmitted, //提交事件 inputFormatters, //限制输入的文字的格式 bool enabled, //是否可编辑 double cursorWidth: 2.0,//光标宽度 Radius cursorRadius, //光标圆角 Color cursorColor,//光标颜色 Brightness keyboardAppearance, EdgeInsets scrollPadding: const EdgeInsets.all(20.0), DragStartBehavior dragStartBehavior: DragStartBehavior.down, bool enableInteractiveSelection, onTap:(){},//点击事件 )
Row:行 Column:列(如果你的内容超出了Row或者column的宽度或者高度,那么会报错页面会显示黄黑条纹,证明溢出了)
Row( Key key, MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start, //主轴的对齐方向 水平是主轴 MainAxisSize mainAxisSize: MainAxisSize.max, //布局的宽高值 CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center, //非主轴的对齐方式 TextDirection textDirection, //Row 子级的排列顺序 VerticalDirection verticalDirection: VerticalDirection.down,//Column 子级的排列顺序 TextBaseline textBaseline, //子组件对齐的,只不过对齐的是字符的基线 List<Widget> children: const <Widget> []//放置自己 )
Flex:弹性布局允许子widget按照一定比例来分配父容器空间(和Row、Column类似)
Flex( Key key, Axis direction, //样式 边框之类的 MainAxisAlignment mainAxisAlignment: MainAxisAlignment.start, MainAxisSize mainAxisSize: MainAxisSize.max, CrossAxisAlignment crossAxisAlignment: CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection: VerticalDirection.down, TextBaseline textBaseline, List<Widget> children: const <Widget> []//子级 )
Expand:可以按比例“扩伸”Row、Column和Flex子widget所占用的空间。
Expanded( Key key, int flex: 1, Widget child )
Wrap和Flow:支持流式布局,可以在要溢出的时候自动换行(Wrap对比Row Flow对比Column Flow尽量少用,因为太过复杂了)
Wrap( Key key, Axis direction: Axis.horizontal, WrapAlignment alignment: WrapAlignment.start, double spacing: 0.0, //主轴方向子widget的间距 WrapAlignment runAlignment: WrapAlignment.start, double runSpacing: 0.0, //纵轴方向的间距 WrapCrossAlignment crossAxisAlignment: WrapCrossAlignment.start, TextDirection textDirection, VerticalDirection verticalDirection: VerticalDirection.down, List<Widget> children: const <Widget> []//子级 )
Stack Positioned :层叠(经常一块使用)
Stack( Key key, AlignmentGeometry alignment: AlignmentDirectional.topStart, //如何去对齐没有定位 TextDirection textDirection, StackFit fit: StackFit.loose, //用于决定没有定位的子widget如何去适应Stack的大小 Overflow overflow: Overflow.clip, //决定如何显示超出Stack显示空间的子widget List<Widget> children:[ Image('src'), Positioned( Key key, double left, double top, double right, double bottom, double width, double height, Widget child ) ] )
Container:容器
Container(
Key key,
AlignmentGeometry alignment,//子级对齐
EdgeInsetsGeometry padding,
Color color, //颜色
Decoration decoration,// 背景装饰
Decoration foregroundDecoration, //前景装饰
double width,
double height,
BoxConstraints constraints, //容器大小的限制条件
EdgeInsetsGeometry margin,
Matrix4 transform, //变换
Widget child
)
ConstrainedBox:限制容器
ConstrainedBox( Key key, constraints: BoxConstraints( minWidth: double.infinity, //宽度尽可能大 minHeight: 50.0 //最小高度为50像素 ), Widget child )
BoxDecoration:装饰容器
BoxDecoration( Color color, //颜色 DecorationImage image, //图片 BoxBorder border, //边框 BorderRadiusGeometry borderRadius, //圆角 List<BoxShadow> boxShadow, //阴影 Gradient gradient, BlendMode backgroundBlendMode, BoxShape shape: BoxShape.rectangle )
ListView:水平列表
ListView( Key key, Axis scrollDirection: Axis.vertical, //水平列表还是垂直列表 bool reverse: false, //翻转 ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, //是否根据子widget的总长度来设置ListView的长度 EdgeInsetsGeometry padding, double itemExtent, //控制子控件在滚动方向上的长度,所以它跟scrollDirection是密切相关的 bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, List<Widget> children: const <Widget> [], int semanticChildCount, DragStartBehavior dragStartBehavior: DragStartBehavior.down )
GridView:类似表格的那种布局
GridView( Key key,
gridDelegate:SliverDelegateWithFixedCrossAxiaCount(
crossAxisCount:2,//横轴两个子级
childAspextRatio:1.0//宽高比为1
mainAxisSpacing:0.0,//主轴间隔
crossAxisSpacing:0.0,//横轴间隔
), Axis scrollDirection: Axis.vertical, //水平还是垂直 bool reverse: false, //翻转 ScrollController controller, bool primary, ScrollPhysics physics, bool shrinkWrap: false, EdgeInsetsGeometry padding, SliverGridDelegate gridDelegate, bool addAutomaticKeepAlives: true, bool addRepaintBoundaries: true, bool addSemanticIndexes: true, double cacheExtent, List<Widget> children: const <Widget> [], int semanticChildCount )
GestureDetector:手势(交互事件在这里面都有)
GestureDetector( Key key,
Widget child, (TapDownDetails) → void onTapDown, (TapUpDetails) → void onTapUp, () → void onTap, () → void onTapCancel, () → void onDoubleTap, () → void onLongPress, () → void onLongPressUp, (GestureLongPressDragStartDetails) → void onLongPressDragStart, (GestureLongPressDragUpdateDetails) → void onLongPressDragUpdate, (GestureLongPressDragUpDetails) → void onLongPressDragUp, (DragDownDetails) → void onVerticalDragDown, (DragStartDetails) → void onVerticalDragStart, (DragUpdateDetails) → void onVerticalDragUpdate, (DragEndDetails) → void onVerticalDragEnd, () → void onVerticalDragCancel, (DragDownDetails) → void onHorizontalDragDown, (DragStartDetails) → void onHorizontalDragStart, (DragUpdateDetails) → void onHorizontalDragUpdate, (DragEndDetails) → void onHorizontalDragEnd, () → void onHorizontalDragCancel, (ForcePressDetails) → void onForcePressStart, (ForcePressDetails) → void onForcePressPeak, (ForcePressDetails) → void onForcePressUpdate, (ForcePressDetails) → void onForcePressEnd, (DragDownDetails) → void onPanDown, (DragStartDetails) → void onPanStart, (DragUpdateDetails) → void onPanUpdate, (DragEndDetails) → void onPanEnd, () → void onPanCancel, (ScaleStartDetails) → void onScaleStart, (ScaleUpdateDetails) → void onScaleUpdate, (ScaleEndDetails) → void onScaleEnd, HitTestBehavior behavior, bool excludeFromSemantics: false, DragStartBehavior dragStartBehavior: DragStartBehavior.down )
StatelessWidget和StatefulWidget
1.StatelessWidget:无中间状态变化的widget,需要更新展示内容就得通过重新new,flutter推荐尽量使用StatelessWidget
2.StatefullWidget:存在中间状态变化,那么问题来了,widget不是都immutable的,状态变化存储在哪里?flutter 引入state的类用于存放中间态,通过调用state.setState()进行此节点及以下的整个子树更新
二、注意
1.在dart中如果需要将变量变成私有的可以在变量名字前面加下划线 _name 就可以了;
2.有的组件具有点击效果比如LnkWall 有一个onTap表示点击,但是有的并没有点击函数。所以我们可以把这个组件放到手势里面;
三、理解
1.几种移动端开发的技术对比
React Native 是接近原生; 需要些适配代码; 60fps(帧)
Html5 就是嵌入页面; 需要适配代码;
Flutter 可以和原生开发一致甚至超过原生; 不需要直接一套代码就可以了; 120fps (帧) 基于C++开发 原生的是基于Java开发的
2.引入dart文件或者包
<1>.import 组件路径 show 需要导入的组件名称;//本地组件 只引入组件名字的,如果没有写名字那么就是全部引入
<2>.import 'package:包名称';//要引入的dart文件
在pubspec.yaml文件中将包的版本写上,就可以了
1 dependencies: 2 flutter: 3 sdk: flutter 4 cupertino_icons: ^0.1.2 5 http : ^0.12.0 6 dio: ^2.1.0 7 date_range_picker: ^1.0.5
<3>.一个dart文件作为另一个文件的一部分
在父中:part './book/Featured.dart';
在子中:part of '../book.dart';
3.数据交互
第一种方法
import 'package:http/http.dart' as http;//包 import 'dart:convert';//包 class GetData extends StatefulWidget{ _StateGetData createstate()=>_StateGetData() } class _StateGetData extends State<GetData>{ Future _getDataInfo() async{ final url=Uri.http('10.0.2.2:8081','/home',{'mark':'春季特惠房间','address':widget.mark}); final result=await http.get(url); setState((){ data=json.decode(result.body).toList(); }); } @override void initState(){ super.initState(); _getDataInfo(); } Widget build(BuildContext context){ return Container() } }
第二种方法
import 'package:http/http.dart' as http;//包 import 'dart:convert';//包 class GetData extends StatefulWidget{ _StateGetData createstate()=>_StateGetData() } class _StateGetData extends State<GetData>{ _getDataInfo(){ final url=Uri.http('10.0.2.2:8081','/home',{'mark':'春季特惠房间','address':widget.mark}); final result=http.get(url); return result } @override Widget build(BuildContext context){ FutureBuilder( future:_getDataInfo(), builder:(BuildContext context,snap){ return snap.data } ) return Container() } }
4.路由
main.dart
return new MaterialApp( title: 'Flutter Demo', home: new MyHomePage(title: '应用程序首页'), routes: <String, WidgetBuilder> { '/a': (BuildContext context) => new MyPage(title: 'A 页面'), '/b': (BuildContext context) => new MyPage(title: 'B 页面'), '/c': (BuildContext context) => new MyPage(title: 'C 页面') }, );
1.page1-page2
page1
Navigator.pushNamed(context,'/page2')
2.page1-page2带参数
page1
Navigator.of((context).push(MaterialPageRoute(
builder: (context) {
return new Page2("传入跳转参数");
}
));
3.page2-page1带参数
page2
Navigator.of(context).pop("我是来自dymamic 关闭的返回值");
5.flutter底层渲染
我们在开发android或者ios的时候用的语言是不一样,但是最终的图形计算和绘制都是由相应的硬件来完成,而直接操作硬件的指令通常都会有操作系统屏蔽,应用开发者通常不会直接面对硬件,操作系统屏蔽了这些底层硬件操作后会提供一些封装后的API供操作系统之上的应用调用,但是对于应用开发者来说,直接调用这些操作系统提供的API是比较复杂和低效的,因为操作系统提供的API往往比较基础。
Flutter的原理正是如此,它提供了一套Dart API,然后在底层通过OpenGL这种跨平台的绘制库(内部会调用操作系统API)实现了一套代码跨多端。由于Dart API也是调用操作系统API,所以它的性能接近原生。
6.Element和BuildContext的区别
根据Widget生成Element,然后创建相应的RenderObject并关联到Element.renderObject属性上,最后再通过RenderObject来完成布局排列和绘制。
四、资料
1.官网:https://flutter.dev/
2.中文网站:https://flutterchina.club/
3.dart package:https://pub.dartlang.org/
4.Icon:https://material.io/tools/icons/?icon=favorite_border&style=baseline
5.数据可以放在firebase