【Flutter】开发之基础Widget(三)

什么是 Widget

Flutter 的核心设计思想便是一切即 Widget,在 Flutter 的世界里,包括viewsviewcontrollerslayouts等在内的概念都建立在 Widget 之上,可以理解成原生的View

lib/main.dart 是程序的主入口

//导包
import 'package:flutter/material.dart';
//程序入口
void main() => runApp(MyApp());
//相当于主页面
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue, 
      ),
      home: MyHomePage(title: 'Home Page'),
    );
  }
}

可以看到,这个返回了一个MaterialAppWidget,作为程序的主界面。

父级组件

Widget 介绍
StatelessWidget 无状态widget,类似静态页面,不与用户交互
StatefulWidget 有状态widget,可以改变,可以与用户交互

基础组件

Widget 介绍
MaterialApp 一般用作APP顶层的主页入口,可配置主题,多语言,路由等
Scaffold 一般用户页面的承载Widget,包含appbar、snackbar、drawer等material design的设定。
Appbar 一般用于Scaffold的appbar ,内有标题,二级页面返回按键等,当然不止这些,tabbar等也会需要它
Text 显示文本,类似于TextView
Image 显示图片,可以加载本地资源、file、网络图片、内存图片
TextField 输入框,类似于EditText
  • Text
          Text(
          //文本
          '我是Text我是Text我是Text我是Text我是Text我是Text我是Text我是Text我是Text我是Text',
          //超出屏幕 clip裁剪,fade渐隐,ellipsis省略号
          overflow: TextOverflow.ellipsis,
          //对齐方式
          textAlign: TextAlign.center,
          //文本方向
          textDirection: TextDirection.rtl,
          //样式
          style: TextStyle(
            color: Colors.lightBlue,
            fontSize: 14,
            fontStyle: FontStyle.italic,
            backgroundColor: Colors.black87,
            //none无文字装饰,lineThrough删除线,overline文字上面显示线,underline文字下面显示线
            decoration: TextDecoration.lineThrough,
            //字母间隙
            letterSpacing: 10,
          ),
        )
image.png
  • Image
方法 作用
Image.assetImage(image: new AssetImage() 加载本地图片
Image.fileImage(image: new FileImage() file
Image.memoryImage(image: new MemoryImage() 加载内存byte数组
Image.networkImage(image: new NetworkImage() 加载网络图片

其中,asset首先需要在根目录下建立images文件夹,然后在pubspec.yaml文件中添加引用才能使用

flutter:
  uses-material-design: true
  assets:
    - images/ic_launcher.png
              Image.asset(
                'images/ic_launcher.png',
                width: 100,
                height: 100,
                fit: BoxFit.fitHeight,
              ),

              Image(
                image: new NetworkImage(
                    'http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg'),
                width: 100,
                height: 100,
                fit: BoxFit.cover,
              )
image.png
  • TextField
        TextField(
            //键盘输入方式
            keyboardType: TextInputType.number,
            decoration: InputDecoration(
              //提示文字
              hintText: '请输入手机号',
              //内容边距
              contentPadding: EdgeInsets.all(10),
              //提示文字样式
              hintStyle:
                  TextStyle(color: Colors.deepOrangeAccent, fontSize: 18),
              //边框
              border: OutlineInputBorder(
                //圆角
                borderRadius: BorderRadius.all(Radius.circular(4)),
                borderSide: BorderSide(color: Colors.deepOrange),
              ),
            ),
            //文字改变时调用
            onChanged: (String content) {
              print("content=" + content);
            },
            //光标颜色
            cursorColor: Colors.deepOrangeAccent,
            //光标圆角
            cursorRadius: Radius.circular(4),
            //光标宽度
            cursorWidth: 2,
          )

布局型

Widget 多个子Widget 介绍
Container 默认充满,包含了padding、margin、color、宽高、decoration 等配置
Padding 用于设置padding,对,你没有猜错,绝大部分Widget是没有padding属性的
Center 用于居中显示
Column 垂直布局,类似于LinearLayout 的orientation="vertical"
Row 水平布局,类似于LinearLayout 的orientation="horizontal"
Stack 类似于relativeLayout 或者FrameLayout
ListView 类似于ListView或者RecyclerView
  • Container
  • Padding
  • Column
  • Row
class ContainerDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ContainerDemo'),
      ),
      body: Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.only(left: 10, right: 20),
//        color: Colors.orangeAccent,
        decoration: new BoxDecoration(
            //设置了decoration的color,就不能设置Container的color,否则会报错
            color: Colors.white,
            borderRadius: BorderRadius.all(Radius.circular(10)),
            border: new Border.all(width: 10, color: Colors.blue)),
        child: Column(
          //Column 垂直方向,Row 水平方向
          mainAxisAlignment: MainAxisAlignment.center,
          //max相当于match_parent,min相当于wrap_content
          mainAxisSize: MainAxisSize.max,
          verticalDirection: VerticalDirection.up,
          children: <Widget>[
            Container(
              padding: EdgeInsets.all(10),
              margin: EdgeInsets.all(20),
              color: Colors.black54,
              child: Text(
                '1111111',
              ),
            ),
            Text(
              '111FFFFg',
              style: TextStyle(
                fontSize: 18,
                backgroundColor: Colors.black54,
              ),
            ),
            Text('222'),
            Text('333'),
          ],
        ),
      ),
    );
  }
}
  • Stack

Stack 类似于relativeLayout 或者FrameLayout,有2种定位方式

1.alignment 作用于是全部的子Widget

class StackDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Stack(
        textDirection: TextDirection.ltr,
        //以整个组件的中心为坐标原点,x、y 偏移量取值范围为 [-1,1],
        // 如果 x 的偏移量大于 0,则表示向右偏移,小于 0 则向左偏移;
        // 如果 y 轴的偏移量大于 0 则向下偏移,小于 0 则向上偏移。
//        alignment: Alignment(0, 0),
        //AlignmentDirectional.topStart:垂直靠顶部水平靠左对齐
        //AlignmentDirectional.topCenter:垂直靠顶部水平居中对齐
        //AlignmentDirectional.topEnd:垂直靠顶部水平靠右对齐
        //AlignmentDirectional.centerStart:垂直居中水平靠左对齐
        //AlignmentDirectional.center:垂直和水平居中都对齐
        //AlignmentDirectional.centerEnd:垂直居中水平靠右对齐
        //AlignmentDirectional.bottomStart:垂直靠底部水平靠左对齐
        //AlignmentDirectional.bottomCenter:垂直靠底部水平居中对齐
        //AlignmentDirectional.bottomEnd:垂直靠底部水平靠右对齐
        alignment: AlignmentDirectional.centerEnd,
        children: <Widget>[
          Container(
            color: Colors.black54,
            child: Text(
              '1111111',
            ),
          ),
          Text('111FFFFg',
              style: TextStyle(fontSize: 18, backgroundColor: Colors.black54)),
          Text('22222222')
        ],
      ),
    );
  }
}

image.png

2.Positioned
只能控制单个Widget,主要有leftrighttopbottomwidthheight几个属性,分别表示距左、右、上、下的边距,长度和宽度
注意:
1)leftright并存时,left生效;topbottom并存时,top生效
2)leftrightwidth不能并存,topbottomheight不能并存,会报错

class StackDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: Stack(
        textDirection: TextDirection.ltr,
       children: <Widget>[
          Container(
            color: Colors.black54,
            child: Text(
              '1111111',
            ),
          ),
          Positioned(
            top: 100,
            child: Text(
              '111FFFFg',
              style: TextStyle(
                fontSize: 18,
                backgroundColor: Colors.black54,
              ),
            ),
          ),
          Positioned(
            child: Text('22222222'),
            right: 10,
            top: 200,
          )
        ],
      ),
    );
  }
}
image.png
  • ListView
    主要有3种构造方式
    ListView.builder
    ListView.separated
    ListView.custom

1.ListView.builder
使用自带的item --ListTile

class ListViewDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListViewDemo'),
        centerTitle: true,
      ),
      body: Container(
        color: Colors.white,
        child: ListView.builder(
          //item
          itemBuilder: (context, index) {
            return ListTile(
              //前置图标
              leading: new Icon(Icons.list),
              title: new Text('标题'),
              subtitle: new Text('副标题'),
              //后置图标
              trailing: new Icon(Icons.arrow_forward_ios),
              //内容边距
              contentPadding: EdgeInsets.all(10),
            );
          },
          //数量
          itemCount: 10,
          //内容适配
          shrinkWrap: true,
          //内边距
          padding: EdgeInsets.only(left: 10),
          //是否倒叙
          reverse: false,
          //item 高度 让item加载更加高效
          itemExtent: 50,

          //滑动方式
          //AlwaysScrollableScrollPhysics() 总是可以滑动
          //NeverScrollableScrollPhysics禁止滚动
          //BouncingScrollPhysics 内容超过一屏 上拉有回弹效果
          //ClampingScrollPhysics 包裹内容 不会有回弹
          physics: BouncingScrollPhysics(),
          //预加载
          cacheExtent: 10,
        ),
      ),
    );
  }
}

image.png

2.ListView.separated
相当于原生中的多类型,核心是separatorBuilder,与itemBuilder是一同渲染的,可以用它来实现分割线

ListView.separated(
          itemBuilder: (context, index) {
            return ListTile(
              //前置图标
              leading: new Icon(Icons.list),
              title: new Text('标题'),
              subtitle: new Text('副标题'),
              //后置图标
              trailing: new Icon(Icons.arrow_forward_ios),
              //内容边距
              contentPadding: EdgeInsets.all(10),
            );
          },
          separatorBuilder: (context, index) {
            return Divider(
              color: Colors.black45,
              height: 10,
              //左边缩进
              indent: 50,
            );
          },
          itemCount: 20,
        )

image.png

3.ListView.custom
前2种方式是此方式的快捷方式,虽然不常用,但还是要了解下

        ListView.custom(
          childrenDelegate: SliverChildBuilderDelegate((context, index) {
            return ListTile(
              //前置图标
              leading: new Icon(Icons.list),
              title: new Text('标题 custom'),
              subtitle: new Text('副标题 custom'),
              //后置图标
              trailing: new Icon(Icons.arrow_forward_ios),
              //内容边距
              contentPadding: EdgeInsets.all(10),
            );
          }),
        )

效果同方式1

示例

模拟器上间隔线显示有问题,真机正常

image.png

ListViewDemo相关代码

class ListViewDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListViewDemo'),
        centerTitle: true,
      ),
      body: Container(
        color: Colors.white,
        child: ListView.separated(
          itemBuilder: ((context, index) {
            return MoveItem();
          }),
          separatorBuilder: (context, index) {
            return Divider(
              color: Colors.black45,
              height: 10,
            );
          },
          itemCount: 10,
        ),
      ),
    );
  }
}

MoveItem相关代码

class MoveItem extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.all(4),
      child: Row(
        children: <Widget>[
          ClipRRect(
            borderRadius: BorderRadius.circular(4),
            child: Image.network(
              'http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg',
              width: 100,
              height: 150,
              fit: BoxFit.fill,
            ),
          ),
          Padding(
            padding: EdgeInsets.only(left: 15),
          ),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: <Widget>[
              Text(
                '狄仁杰之四大天王',
                style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
              ),
              Text('豆瓣评分6.6'),
              Text('类型:动作、惊悚、冒险'),
              Text('导演:徐克'),
              Row(
                children: <Widget>[
                  Text('主演:'),
                  Padding(
                    padding: EdgeInsets.only(left: 10),
                  ),
                  Container(
                    width: 40,
                    height: 40,
                    child: CircleAvatar(
                      backgroundImage: NetworkImage(
                          'http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg'),
                    ),
                  ),
                  Container(
                    width: 40,
                    height: 40,
                    margin: EdgeInsets.only(left: 10),
                    child: CircleAvatar(
                      backgroundImage: NetworkImage(
                          'http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg'),
                    ),
                  ),
                  Container(
                    width: 40,
                    height: 40,
                    margin: EdgeInsets.only(left: 10),
                    child: CircleAvatar(
                      backgroundImage: NetworkImage(
                          'http://n.sinaimg.cn/sports/2_img/upload/cf0d0fdd/107/w1024h683/20181128/pKtl-hphsupx4744393.jpg'),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ],
      ),
    );
  }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容