Flutter学习3-Flutter基础组件

Widget

Flutter中一切皆为Widget,Widget是Flutter应用界面的基本构成单元,每个widget都与最终的用户界面展示紧密相关. 一个widget可以定义如下:

  • 一个结构元素(一个按钮,一个菜单)
  • 一个风格元素(字体,配色方案等)
  • 布局(padding,margin)
  • 等等

什么是widget

abstract class Widget extends DiagnosticableTree {
  const Widget({ this.key });
  
  final Key key;
  
  @protected
  @factory
  Element createElement();
  
  static bool canUpdate(Widget oldWidget, Widget newWidget) {
    return oldWidget.runtimeType == newWidget.runtimeType
        && oldWidget.key == newWidget.key;
  }
}
复制代码
  • widget 是个抽象类
  • 其中 canUpdate() 决定是否重新绘制

widget分类

StatelessWidget 关键代码

内部没有保存状态,UI创建后就不会改变

abstract class StatelessWidget extends Widget {
  const StatelessWidget({ Key key }) : super(key: key);
  @override
  StatelessElement createElement() => StatelessElement(this);
  @protected
  Widget build(BuildContext context);
}
复制代码

StateFullWidget

内部保存了状态,调用setState方法,变成UI

abstract class StatefulWidget extends Widget {
  const StatefulWidget({ Key key }) : super(key: key);
  @override
  StatefulElement createElement() => StatefulElement(this);
  
  @protected
  @factory
  State createState();
}
复制代码

State

关键代码

abstract class State<T extends StatefulWidget> with Diagnosticable {

  T get widget => _widget;
  T _widget;

  BuildContext get context => _element;
  StatefulElement _element;

  bool get mounted => _element != null;

  @protected
  @mustCallSuper
  void initState() {
   
  }

  @mustCallSuper
  @protected
  void didUpdateWidget(covariant T oldWidget) { }

  @protected
  @mustCallSuper
  void reassemble() { }

  @protected
  void setState(VoidCallback fn) {
    final dynamic result = fn() as dynamic;
    _element.markNeedsBuild();
  }

  @protected
  @mustCallSuper
  void deactivate() { }

 
  @protected
  @mustCallSuper
  void dispose() {

  }

  @protected
  Widget build(BuildContext context);

  @protected
  @mustCallSuper
  void didChangeDependencies() { }
}
复制代码

State生命周期

  • initState():被插入到widget树中时被调用一次
  • didChangeDependencies():当state对象的依赖发生变化时调用
  • build():构建widget时调用
  • didUpdateWidget():widget重新构建时调用
  • deactivate(): 当state对象从树中被移除时调用
  • dispose(): 当state对象从树中被永久移除时调用,一般在此方法中释放资源

Widget&Element&RenderObject

  • widget是为element描述需要的配置,负责创建element,决定element是否需要更新
  • element表示widget配置树的特定位置的一个实例,同时持有widget和renderobject,负责管理widget配置和renderobject渲染
  • renderobject表示渲染树的一个对象,负责真正的渲染工作,比如测量,位置,绘制等

Flutter常用基础组件

常用StatelessWidget

Text

  • 文本显示控件
  _buildText() {
    TextStyle style = TextStyle(
        color: Colors.green,//文字颜色
        fontSize: 20,//文字大小
        fontStyle: FontStyle.italic,//设置斜体
        fontWeight: FontWeight.bold);//设置加粗

    return Text("我是一段文字", style: style);
  }
复制代码

Container

  • 容器布局,常用作给子widget设置边距,背景,圆角等效果
  _buildContainer() {
    return Container(
      alignment: Alignment.center,//居中对齐
      padding: EdgeInsets.all(10),//设置内边距
      margin: EdgeInsets.only(left: 20, right: 20),//设置外边距
      decoration: BoxDecoration(//设置装饰器
          color: Colors.greenAccent,//设置颜色
          borderRadius: BorderRadius.all(Radius.circular(5)),//设置圆角
          gradient: LinearGradient(colors: [Colors.deepPurple, Colors.pinkAccent])),//设置渐变色背景
      child: _buildText(),
    );
  }
复制代码

Icon 图标

  • Icon可以是矢量图,所以可以设置大小和颜色
 _buildIcon() {
    return Icon(Icons.android,//图标源
        size: 50, //大小
        color: Colors.greenAccent//图标颜色
    );
  }
复制代码

CloseButton&BackButton

 CloseButton(),
 BackButton()
复制代码

Chip

  • Material的设计小部件
  _buildChip() {
    return Chip(
      backgroundColor: Colors.greenAccent,//背景颜色
      avatar: Icon(Icons.phonelink_off_rounded,color: Colors.pink,),//图标,通过这个设置图标大小
      label: Text('我是Chip的文字'),//文字
      labelPadding: EdgeInsets.only(left: 20),//文字的边距
      labelStyle: TextStyle(color: Colors.white, fontSize: 10),//文字样式
      padding: EdgeInsets.only(left: 10, right: 10, top: 5, bottom: 5),//Chip内边距
      elevation: 5,
    );
  }
复制代码

Divider

  • 分割线widget
  _buildDivider() {
    return Divider(
      height: 50,//分割线占据的高度
      thickness: 5,//分割线高度
      indent: 20,//左边距
      endIndent: 20,//右边距
      color: Colors.blue,//颜色
    );
  }
复制代码

Card

  • 卡片widget,布局中经常用到
  _buildCart() {
    return Card(
        margin: EdgeInsets.all(10),//card外边距
        color: Colors.greenAccent,//背景色
        shadowColor: Colors.pinkAccent,//
        elevation: 5,//阴影
        shape: RoundedRectangleBorder(//圆角形状,默认也为RoundedRectangleBorder
          borderRadius: BorderRadius.all(Radius.circular(6.0))//设置圆角大小
        ),
        child: Container(
          padding: EdgeInsets.only(left: 10, top: 5, right: 10, bottom: 5),
          child: _buildText(),
        ));
  }
复制代码

AlterDialog

  • 弹窗
_buildRaisedButton(BuildContext context) {
  return RaisedButton(
      onPressed: () {
        showDialog(//显示弹框的方法
            context: context,
            builder: (context) {
              return _buildAlterDialog(context);
            });
      },
      child: Text('显示弹框'));
}

AlertDialog _buildAlterDialog(BuildContext context) {
  return AlertDialog(
    title: Text('我是标题了'),
    content: Text('我是内容啊'),
    actions: [
      //配置下面的按钮
      FlatButton(
          onPressed: () {
            Navigator.of(context).pop(); //关闭弹框
          },
          child: Text("确认"))
    ],
  );
}
复制代码

FloatingActionButton

  • 也是Material下的一个widget
_buildFloatingActionButton() {
  return FloatingActionButton(
    onPressed: () {},
    child: Icon(Icons.add),
  );
}
复制代码

Column&Row

  • 垂直容器布局,和Android中Linerlayout差不多

Colum 有主轴和交叉轴的概念,Column是垂直布局,它的主轴就是垂直方向,交叉轴是水平方向;Row 是水平方向布局,它的主轴是水平方向,它的交叉轴 就是垂直方向

  _buildColumn() {
    return Column(
      mainAxisSize: MainAxisSize.max, //主轴方向的大小
      //主轴位置,Column是是垂直布局,所以垂直方向是主轴
      mainAxisAlignment: MainAxisAlignment.start, //垂直方向从顶部开始
      //交叉轴位置,和主轴十字交叉的轴,也是水平方向()
      crossAxisAlignment: CrossAxisAlignment.end,//水平方向
      children: [
        //填充其中的子widget
        _buildText(),
        _buildText(),
      ],
    );
  }
复制代码

常用StatefulWidget

Image

  • 图片控件,可以显示网络图片和项目中的资源图片
        Image.network(
          'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/96119b38be4be1dafc95fcbff0d9ee30~300x300.image',
          fit: BoxFit.cover,//填充方式,跟Android里中scaleType的几种方式差不多
          width: 60,
          height: 60,
        )
复制代码

TextField

  • 文本输入组件
        TextField(
          maxLength: 11,//最大长度
          keyboardType: TextInputType.number,//输入键盘类型
          // obscureText: true,//是否明文显示
          inputFormatters: [
            FilteringTextInputFormatter.digitsOnly//输入类型
          ],
          textInputAction: TextInputAction.search,//键盘右下角文字
          controller: TextEditingController(text: '86'),//默认文本
          decoration: InputDecoration(
              contentPadding: EdgeInsets.only(left: 10, right: 10),
              hintText: '请您输入电话号码',
              hintStyle: TextStyle(fontSize: 20, color: Colors.black12)),
        )
复制代码

AppBar

  • 标题栏
_buildAppBar() {
  return AppBar(
    title: Text('我是标题'), //设置标题
    actions: [CloseButton(), BackButton()],//设置一些后面的按钮
    centerTitle: true, //标题居中
    toolbarHeight: kToolbarHeight,//标题栏高度
    textTheme: TextTheme(), //设置样式
  );
}
复制代码

RefreshIndicator

  • 刷新组件,child为ListView或CustomScrollView
_buildList() {
  return RefreshIndicator(
      child: ListView(
        children: [
          Text('列表内容1'),
          Text('列表内容1'),
          Text('列表内容1'),
          Text('列表内容1'),
          Text('列表内容1'),
        ],
      ),
      onRefresh: handRefresh);
}

Future<Null> handRefresh() async {
  await Future.delayed(Duration(microseconds: 1000));
  return null;
}
复制代码

PageView

  • 轮播的widget跟Android中ViewPage差不多
_buildPageView() {
  return Container(
    height: 100,
    margin: EdgeInsets.only(top: 10),//设置距离顶部高度
    child: PageView(//PageView必须设置高度,所以用一个Container包裹起来
      children: [//设置每个item
        Container(
          alignment: Alignment.center,//item居中显示
          margin: EdgeInsets.only(left: 20, right: 20),//设置item左右边距
          decoration: BoxDecoration(
              color: Colors.greenAccent,
              borderRadius: BorderRadius.all(Radius.circular(5))),//设置圆角
          child: Text('page1'),
        ),
        Container(
          alignment: Alignment.center,
          margin: EdgeInsets.only(left: 20, right: 20),
          decoration: BoxDecoration(
              color: Colors.green,
              borderRadius: BorderRadius.all(Radius.circular(5))),
          child: Text('page2'),
        ),
        Container(
          alignment: Alignment.center,
          margin: EdgeInsets.only(left: 20, right: 20),
          decoration: BoxDecoration(
              color: Colors.lightGreen,
              borderRadius: BorderRadius.all(Radius.circular(5))),
          child: Text('page3'),
        ),
      ],
    ),
  );
}
复制代码

BottomNavigationBar

  • 底部导航栏
class HomePage extends State<HomePageState> {
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: _buildAppBar(),//包含状态栏
      bottomNavigationBar: BottomNavigationBar(//底部导航
        currentIndex: _currentIndex,//当前选中位置
        onTap: (index) {//点击回调
          setState(() {
            _currentIndex = index;
          });
        },
        items: [//items,至少为2个
          BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: '首页',
              activeIcon: Icon(
                Icons.home,
                color: Colors.deepPurple,
              )),
          BottomNavigationBarItem(
              icon: Icon(Icons.list),//默认状态图标
              label: '列表',
              activeIcon: Icon(//选中状态图标
                Icons.list,
                color: Colors.deepPurple,
              )),
        ],
      ),
      body: _currentIndex == 0 ? _buildMain() : _buildList(),//内容
      floatingActionButton: _buildFloatingActionButton(),//按钮
    );
  }
}
复制代码

Scaffold

  • 容器布局,提供了一些列的widget,能帮助我们快速搭建一个页面,从上面的代码中可以看到,其中有actionbar,底部导航,floatactionbar等供我们一键生成组件

MaterialApp

  • 一般作为程序入口,配置App整体的风格,样式,默认属性等等
void main() {
  runApp(MyFirstApp());
}
class MyFirstApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '使用materialApp',
      theme: ThemeData(
        //这里能配置整个App的各种属性,比如主题色,文本输入框获取焦点后颜色等等
        primarySwatch: Colors.deepPurple,//设置主题色
        visualDensity: VisualDensity.adaptivePlatformDensity,//设置单位适配方式
      ),
      home: HomePage(),
    );
  }
}

复制代码

Flutter其他widget

ClipOval

  • ClipOval将其子widget裁剪成圆形

Opacity

  • Opacity 对子widget进行透明度改变
_buildOpacityAndClipOval() {
  return Opacity(
    opacity: 0.5,//透明度
    child: ClipOval(
      child: Image.network(
        'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/96119b38be4be1dafc95fcbff0d9ee30~300x300.image',
        fit: BoxFit.cover,
        width: 60,
        height: 60,
      ),
    ),
  );
}
复制代码

ClipRRect和ClipRect

  • ClipRRect:将子widget裁剪成圆角矩形
  • ClipRect:将子widget裁剪成矩形
_buildClipRect() {
  return ClipRRect(
    borderRadius: BorderRadius.circular(5),//设置圆角
    clipBehavior: Clip.antiAlias,//抗锯齿
    child: Image.network(
      'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/96119b38be4be1dafc95fcbff0d9ee30~300x300.image',
      fit: BoxFit.cover,
      width: 60,
      height: 60,
    ),
  );
}
复制代码

PhysicalModel

  • PhysicalModel也是负责裁切子widget的
_buildPhysicalModel() {
  return PhysicalModel(
    color: Colors.green,
    elevation: 5,
    borderRadius: BorderRadius.circular(5),
    child: Text('呵呵呵呵呵呵'),
  );
}
复制代码

Center

  • 让子widget居中显示

Sizebox

  • 给子widget设置宽高,如果子widget用设置宽高的属性则用不到了
_buildCenter() {
  return SizedBox(
    width: 180,
    height: 180,
    child: Center(
      child: Image.network(
        'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/96119b38be4be1dafc95fcbff0d9ee30~300x300.image',
        fit: BoxFit.cover,
        width: 60,
        height: 60,
      ),
    ),
  );
}
复制代码

Padding

  • 就是给子widget设置边距的

FractionallySizedBox

  • FractionallySizedBox可以让子widget在水平或者垂直方向上充满屏幕
_buildFractionallySizedBox() {
  return FractionallySizedBox(
      widthFactor: 1,
      child: Container(
        alignment: Alignment.center,
        color: Colors.green,
        height: 50,
        child: Text('呵呵呵呵呵呵'),
      ));
}
复制代码

Stack和 Positioned

  • Stack和Android中Framlayout一样,子widget是层层覆盖的
  • Positioned可以调整子widget在Stack中的位置来显示特殊的效果
_buildStack() {
  return Stack(
    children: [//设置子widget组
      Image.network(
        'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/96119b38be4be1dafc95fcbff0d9ee30~300x300.image',
        fit: BoxFit.cover,
        width: 80,
        height: 80,
      ),
      Positioned(//通过Positioned调整位置
          left: 0,//距离左边
          bottom: 0,//距离底部
          child: Image.network(
            'https://sf1-scmcdn2-tos.pstatp.com/xitu_juejin_web/img/wechat.ce329e6.png',
            fit: BoxFit.cover,
            width: 40,
            height: 40,
          )),
    ],
  );
}
复制代码

Wrap

  • 当有多个子widget的时候,会自动换行
_buildWrap() {
  return Wrap(
    children: [
      Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(5),
        decoration: BoxDecoration(
            color: Colors.green, borderRadius: BorderRadius.circular(10)),
        child: Text('我是一个兵,来自老百姓'),
      ),
      Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(5),
        decoration: BoxDecoration(
            color: Colors.green, borderRadius: BorderRadius.circular(10)),
        child: Text('打倒日本小鬼子,是我的本领'),
      ),
      Container(
        margin: EdgeInsets.all(10),
        padding: EdgeInsets.all(5),
        decoration: BoxDecoration(
            color: Colors.green, borderRadius: BorderRadius.circular(10)),
        child: Text('保卫人民是我的责任'),
      ),
    ],
  );
}
复制代码

Expaned

  • 让子widget铺满某个水平或垂直方向,跟Android中的widget(权重)差不多
//外层是Column
List<Widget> _buildExpanded() {
  var list = <Widget>[];
  list.add(Text("你好"));
  list.add(Expanded(
      child: Container(
    decoration: BoxDecoration(color: Colors.green),
    child: Text('我要充满高度'),
  )));
  return list;
}
复制代码

关于Flutter布局的一些思考

其实刚开始接触这些widget,多少有些抵触,跟Android现有的编写界面组件相比,有点儿太零碎了,实现一种效果,可能有很多种方法,布局的实现感觉是根据个人的习惯决定的,而且要想重构一些页面的布局,不得挺费劲么........目前了解的比较少吧 所以会有这么简单的问题,等以后了解的更多了说不定就不抵触了呢...

真的是选择困难症的一记猛药啊,目前先这样吧...

分类:
Android
标签: