Fork me on GitHub

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

posted @ 2019-04-01 17:06  zhang_yx  阅读(351)  评论(0编辑  收藏  举报