Flutter学习-备忘录

1.页面跳转:
除了Navigator.of(context).pushNamed('pageA');之外还可以通过MaterialPageRoute跳转
MaterialPageRoute 是一种路由模版,它根据平台自适应替换整个页面。
Navigator.push(context, MaterialPageRoute(builder:(BuildContext context) => PageB()))
跳转其它App插件:url_launcher

  1. Isolate/compute 使用:
    Isolate 是分离的运行线程,并且不和主线程的内存堆共享内存。这意味着不能访问主线程中的变量,不能使用setState() 来更新IU。
    Isolate用来处理长期运行或是计算密集型任务。
import 'dart:isolate';
import  'dart:io';

void main() {
  print("main isolate start");
  create_isolate();
  print("main isolate end");
}

// 创建一个新的 isolate
create_isolate() async{
  ReceivePort rp = new ReceivePort();
  SendPort port1 = rp.sendPort;

  Isolate newIsolate = await Isolate.spawn(doWork, port1);

  SendPort port2;
  rp.listen((message){
    print("main isolate message: $message");
    if (message[0] == 0){
      port2 = message[1];
    }else{
      port2?.send([1,"这条信息是 main isolate 发送的"]);
    }
  });
}

// 处理耗时任务
static void doWork(SendPort port1){
  print("new isolate start");
  ReceivePort rp2 = new ReceivePort();
  SendPort port2 = rp2.sendPort;

  rp2.listen((message){
    print("doWork message: $message");
  });

  // 将新isolate中创建的SendPort发送到主isolate中用于通信
  port1.send([0, port2]);
  // 模拟耗时5秒
  sleep(Duration(seconds:5));
  port1.send([1, "doWork 任务完成"]);

  print("new isolate end");
}


import 'package:flutter/foundation.dart';
import  'dart:io';

// 创建一个新的Isolate,在其中运行任务doWork
create_new_task() async{
  var str = "New Task";
  var result = await compute(doWork, str);
  print(result);
}


static String doWork(String value){
  print("new isolate doWork start");
  // 模拟耗时5秒
  sleep(Duration(seconds:5));

  print("new isolate doWork end");
  return "complete:$value";
}
  1. Material组件使用
    Material负责:
    1.Clipping: Material将小部件裁剪为指定的形状,材料的形状是由: [shape], [type], [borderRadius] 这三个属性确定的。
    2.Elevation: 通过elevation像素值在Z轴提升子树,并绘制适当的阴影。
    3.水波纹水墨效果。
 ///注:这是Flutter SDK内的源码
const Material({
    Key key,
    this.type: MaterialType.canvas,
    this.elevation: 0.0,
    this.color,
    this.shadowColor: const Color(0xFF000000),
    this.textStyle,
    this.borderRadius,
    this.shape,
    this.animationDuration: kThemeChangeDuration,
    this.child,
  }) 
// 裁剪:
//shape的类型是ShapeBorder
//BeveledRectangleBorder
//BoxBorder 实现的子类 >>>> Border 和 BorderDirectional
//CircleBorder
//InputBorder 
//RoundedRectangleBorder
//StadiumBorder
        new Material(
        //背景色
          color: Colors.amber,
          shape: new BeveledRectangleBorder(
              side: const BorderSide(
                width: 1.0,
                style: BorderStyle.none,
              ),
              //每个角落的半径
              borderRadius:new BorderRadius.circular(10.0),
          ),
          child: new Container(
            padding: const EdgeInsets.all(10.0),
            child: new Text('你好 Material',style: new TextStyle(fontSize: 14.0),),
          ),
        )

//elevation 海拔和shadowColor 阴影
        new Material(
          color: Colors.amber,//必须要设置颜色
          elevation: 10.0,
          shadowColor: Colors.green,//阴影颜色
          borderRadius: new BorderRadius.circular(8.0),
          type: MaterialType.button,
          child: new Container(
            width: 100.0,
            height: 40.0,
            alignment: Alignment.center,
            child: new Text('你好 Material',textAlign:TextAlign.center,style: new TextStyle(fontSize: 14.0),),
          ),
        )

4.num 类中clamp方法,表示返回在某个范围内的数据

// a 在10-20 范围内
double a=  Random().nextInt(100).toDouble() + Random().nextDouble();
 a = a.clamp(10, 20);
  1. Color.Lerp 颜色渐变方法
    Color.Lerp(a,b,t);
    Color.Lerp返回一个Color,当t为0时返回a,t为1时返回b。当t从0到1时,效果便是从颜色a到颜色b的渐变。

  2. xx.of(context) 方法是向上遍历 Element tree,并找到最近匹配的 xxState。也就是说of实际上是对context跨组件获取数据的一个封装。

7.Scaffold.of(context)一些方法

 // 打开抽屉
Scaffold.of(context).openDrawer()

// 显示底部通知(SnackBar)
Scaffold.of(context).showSnackBar(  
  new SnackBar(content: new Text('Favorite #$index'))   
)
// 移除底部通知(SnackBar)
Scaffold.of(context).removeCurrentSnackBar();

8.随机颜色
Colors.primaries[Random().nextInt(Colors.primaries.length)]

  1. Scrollable,在flutter 中ListView 与GridView 都是继承自BoxScrollView,而 BoxScrollView 继承自ScrollView, ScrollView中持有一个Scrollable
    如果想要为一个控件添加可滚动状态,必须要包含一个组件Scrollable
Scrollable({
    Key key,
    ///滚动方向
    this.axisDirection = AxisDirection.down,
    ///滚动控制器和事件监听
    ///在源码中是这样介绍的  ScrollController.initialScrollOffset  控制初始滚动的位置
    ///ScrollController.keepScrollOffset  控制是否应该自动在[PageStorage]中保存并恢复其滚动位      
    ///置
    ///ScrollController.offset 用来读取当前滚动位置
    this.controller,
    ///决定widget 在用户完成拖拽后的动画响应默认情况下会更护不同环境设置不同的变量
    ///ClampingScrollPhysics  android 使用的水波纹效果
    ///BouncingScrollPhysics:iOS下弹性效果  如果android 想要实现这个效果
    ///子布局高度的综合必须大于listview 的实际高度度即viewport
    this.physics,
    ///  用于生成子布局   类似android 中adapter 的getItem 方法
    @required this.viewportBuilder,
    ///
    this.incrementCalculator,
    /// 是否公开在语义数中,便于类似talkback的软件识别
    this.excludeFromSemantics = false,
    ///语义子集数
    this.semanticChildCount,
    ///处理拖动开始行为的方式与时机 
    ///有两个值 DragStartBehavior.start  DragStartBehavior.down 
    ///从字面理解就   start是从拖动开始,down是从触摸事件按下开始
    this.dragStartBehavior = DragStartBehavior.start,
  })
  1. LayoutBuilder根据组件的大小确认组件的外观
// 当设置父组件的宽高大于100时显示蓝色,小于100时显示红色。
LayoutBuilder(
  builder: (BuildContext context, BoxConstraints constraints) {
    var color = Colors.red;
    if (constraints.maxHeight > 100) {
      color = Colors.blue;
    }
    return Container(
      height: 50,
      width: 50,
      color: color,
    );
  },
)
  1. 滚动视图使用
// ListView
// 一个可滚动的列表 
    1. 固定数量
       ListView(
          children: <Widget>[
            ListTile(title: Text("普通ListView")),
            ListTile(
                title: Text("ListView.build"),
                onTap: () {
                  Navigator.pushNamed(context, '/listview_build');
                }),
          ],
        )
    2.  无限数量
        ListView.builder(
            itemBuilder: (context, index) => Text("Item $index"),
            itemCount: 100)
    3. 需要分割线
        ListView.separated(
            itemBuilder: (context, index) {
              return Text("Item $index");
            },
            separatorBuilder: (context, index) {
              return Container(
                color: Colors.grey,
                height: 3,
              );
            },
            itemCount: 100)
      4.其它自定义item
ListView.custom(childrenDelegate: CustomSliverChildDelegate())
class CustomSliverChildDelegate extends SliverChildDelegate {
  /// 根据index构造child
  @override
  Widget build(BuildContext context, int index) {
    // KeepAlive将把所有子控件加入到cache,已输入的TextField文字不会因滚动消失
    // 仅用于演示
    return KeepAlive(
        keepAlive: true,
        child: TextField(decoration: InputDecoration(hintText: '请输入')));
  }
  /// 决定提供新的childDelegate时是否需要重新build。在调用此方法前会做类型检查,不同类型时才会调用此方法,所以一般返回true。
  @override
  bool shouldRebuild(SliverChildDelegate oldDelegate) {
    return true;
  }
  /// 提高children的count,当无法精确知道时返回null。
  /// 当 build 返回 null时,它也将需要返回一个非null值
  @override
  int get estimatedChildCount => 100;
  /// 预计最大可滑动高度,如果设置的过小会导致部分child不可见,设置报错
  @override
  double estimateMaxScrollOffset(int firstIndex, int lastIndex,
      double leadingScrollOffset, double trailingScrollOffset) {
    return 2500;
  }
  /// 完成layout后的回调,可以通过该方法获已完成布局的视图树包括哪些子控件
  @override
  void didFinishLayout(int firstIndex, int lastIndex) {
    print('didFinishLayout firstIndex=$firstIndex firstIndex=$lastIndex');
  }
}


// NestedScrollView
// 一个可以嵌套其它可滚动widget的widget
NestedScrollView(
  headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
    return <Widget>[SliverAppBar(
      title: Text('title'),
    )];
  },
  body: ListView.builder(itemBuilder: (BuildContext context,int index){
    return Container(
      height: 80,
      color: Colors.primaries[index % Colors.primaries.length],
      alignment: Alignment.center,
      child: Text(
        '$index',
        style: TextStyle(color: Colors.white, fontSize: 20),
      ),
    );
  },itemCount: 20,),
)

// GridView
// 一个可滚动的二维空间数组
1. 固定数量
    GridView.count(
      //水平子Widget之间间距
      crossAxisSpacing: 10.0,
      //垂直子Widget之间间距
      mainAxisSpacing: 30.0,
      //GridView内边距
      padding: EdgeInsets.all(10.0),
      //一行的Widget数量
      crossAxisCount: 2,
      //子Widget宽高比例
      childAspectRatio: 2.0,
      //子Widget列表
      children: getWidgetList(),
    );
2.无限数量
    // SliverGridDelegateWithFixedCrossAxisCount
      GridView.builder(
        itemCount: datas.length,
        //SliverGridDelegateWithFixedCrossAxisCount 构建一个横轴固定数量Widget
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          //横轴元素个数
            crossAxisCount: 3,
            //纵轴间距
            mainAxisSpacing: 20.0,
            //横轴间距
            crossAxisSpacing: 10.0,
            //子组件宽高长度比例
            childAspectRatio: 1.0),
        itemBuilder: (BuildContext context, int index) {
          //Widget Function(BuildContext context, int index)
          return getItemContainer(datas[index]);
      })

    // SliverGridDelegateWithMaxCrossAxisExtent
    GridView.builder(
      itemCount: datas.length,
      itemBuilder: (BuildContext context, int index) {
        return getItemContainer(datas[index]);
      },
      gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
        //单个子Widget的水平最大宽度
        maxCrossAxisExtent: 200,
        //水平单个子Widget之间间距
        mainAxisSpacing: 20.0,
        //垂直单个子Widget之间间距
        crossAxisSpacing: 10.0
      ),
    )
3. 其它自定义
      GridView.custom(
        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 3, mainAxisSpacing: 10.0, crossAxisSpacing: 20.0, ),
        childrenDelegate: SliverChildBuilderDelegate((context, position) {
          return getItemContainer(datas[position]);
        }, childCount: datas.length))

// SingleChildScrollView
// 有一个子widget的可滚动的widget,子内容超过父容器时可以滚动。
      SingleChildScrollView(
        controller: _scrollController,
        reverse: true,
        child: ListBody(
          children: _children(),
        ),
        restorationId: 's1',
      ),

// Scrollable
// 实现了可滚动widget的交互模型,但不包含UI显示相关的逻辑

// Scrollbar
// 一个Material Design 滚动条,表示当前滚动到了什么位置
      Scrollbar(
        radius: Radius.circular(10),
        thickness: 10,
        child: ListView.builder(
          itemBuilder: (context, index) {
            return ListTile(
              title: Text('item $index'),
            );
          },
          itemCount: 30,
        ),
      )
// CustomScrollView
// 一个使用slivers创建自定义的滚动效果的ScrollView
new CustomScrollView(
    shrinkWrap: true,
    // 内容
    slivers: <Widget>[
      new SliverPadding(
             padding: const EdgeInsets.all(20.0),
              sliver: new SliverList(
                 delegate: new SliverChildListDelegate(
                   <Widget>[
                        const Text('A'),
                        const Text('B'),
                        const Text('C'),
                        const Text('D'),
                   ],
                 ),
              ),
     ],
)

// NotificationListener
// 一个用来监听树上冒泡通知的widget。
      NotificationListener<ScrollNotification>(
        onNotification: (notification) {
          ScrollMetrics metrics = notification.metrics;
          print('ScrollNotification####################');
          print('pixels = ${metrics.pixels}');
          print('atEdge = ${metrics.atEdge}');
          print('axis = ${metrics.axis}');
          print('axisDirection = ${metrics.axisDirection}');
          print('extentAfter = ${metrics.extentAfter}');
          print('extentBefore = ${metrics.extentBefore}');
          print('extentInside = ${metrics.extentInside}');
          print('maxScrollExtent = ${metrics.maxScrollExtent}');
          print('minScrollExtent = ${metrics.minScrollExtent}');
          print('viewportDimension = ${metrics.viewportDimension}');
          print('outOfRange = ${metrics.outOfRange}');
          print('ScrollNotification####################');
          return false;
        },
        child: NotificationListener<ScrollUpdateNotification>(
          onNotification: (notification) {
            print('ScrollUpdateNotification####################');
            return false;
          },
          child: NotificationListener<OverscrollNotification>(
            onNotification: (notification) {
              print('OverscrollNotification####################');
              return false;
            },
            child: NotificationListener<ScrollStartNotification>(
              onNotification: (notification) {
                print('ScrollStartNotification####################');
                return false;
              },
              child: NotificationListener<ScrollEndNotification>(
                onNotification: (notification) {
                  print('ScrollEndNotification####################');
                  return false;
                },
                child: _myChild(),
              ),
            ),
          ),
        ),
      ),
    );
// ScrollConfiguration
// 控制可滚动组件在子树中的表现行为
ScrollConfiguration(
  behavior: ScrollBehavior(),
  child: ListView.separated(
    itemBuilder: (BuildContext context, int index) {
      return Text('Item$index');
    },
    separatorBuilder: (BuildContext context, int index){
      return Divider();
    },
    itemCount: 50,
  ),
)

// RefreshIndicator
// Material Design下拉刷新指示器,包装一个可滚动widget
      RefreshIndicator(
        onRefresh: ()async{
          await Future.delayed(Duration(seconds: 5));
        },
        child: ListView(
          children: <Widget>[
             const Text('A'),
             const Text('B'),
             const Text('C'),
             const Text('D'),
          ],
        ),
      ),

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容