Android Flutter:Dart语言(布局篇)

一、Flutter架构

flutter官方文档:https://api.flutter.dev/flutter/widgets/widgets-library.html

flutter架构:

Android Flutter:Dart语言(布局篇)_第1张图片

在flutter的世界里,包括views,view controllers,layouts等在内的概念都建立在Widget之上。widget是flutter功能的抽象描述。通过组合不同的 Widget,来实现我们用户交互界面。

Widget 分为两种:

1、无状态的,StatelessWidget,它只能用来展示信息,不能有动作(用户交互)

使用方法:继承 StatelessWidget,实现 build 方法

class FooWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // ...
  }
}

2、有状态的,StatefulWidget,可以通过改变状态使 UI 发生变化,包含用户交互。

使用方法:稍微复杂,需要一个 State,例子如下

class BarWidget extends StatefulWidget {
  @override
  State createState() {
    return _BarWidgetState();
  }
}

class _BarWidgetState extends State {
  @override
  Widget build(BuildContext context) {
    // ...
  }
}

二、文本Text

使用 TextStyle,可以对文本的样式进行修改

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
       "Put your text here",
       textAlign: TextAlign.center,
       maxLines: 1,
       style: TextStyle(
        color: Colors.blue,
        fontSize: 16.0,
        fontWeight: FontWeight.bold
       ),
    );
  }
}

三、图片Image

Flutter中的图片缩放是fit字段来控制的,缩放属性值在BoxFit枚举中。

有:fill、contain、cover,fitWidth、fitHeight、none、scaleDown

Android Flutter:Dart语言(布局篇)_第2张图片

Android Flutter:Dart语言(布局篇)_第3张图片

图片的来源:网络、文件、资源和内存

Image.asset(name);
Image.file(file);
Image.memory(bytes);
Image.network(src);

例子: 

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {   
    return Image.network(
            'https://gw.alicdn.com/tfs/TB1CgtkJeuSBuNjy1XcXXcYjFXa-906-520.png',
            fit: BoxFit.contain,
            width: 150.0,
            height: 100.0,
    );
  }
}

四、按钮FlatButton 和 RaisedButton

两种按钮的区别在于样式不同。child 参数用于设置按钮的内容。它可以接受任意的 Widget,比方说,Text,Image;

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var flatBtn = FlatButton(
    onPressed: () => print('FlatButton pressed'),
      child: Text('BUTTON'),
    );
    var raisedButton = RaisedButton(
    onPressed: () => print('RaisedButton pressed'),
      child: Text('BUTTON'),
    );
    return raisedButton;
 }
}

五、文本输入框TextField

为了获取用户输入的文本,我们需要给他设置一个 controller。通过这个 controller,就可以拿到文本框里的内容

class MessageForm extends StatefulWidget {
  @override
  State createState() {
    return _MessageFormState();
  }
}

class _MessageFormState extends State {
  var editController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    // Row、Expand 都是用于布局的控件,这里可以先忽略它们
    return Row(
      children: [
      // 占满一行里除 RaisedButton 外的所有空间
      Expanded(
          child: TextField(
            controller: editController,
          ),
        ),
      RaisedButton(
          child: Text("click"),
          onPressed: () => print('text inputted: ${editController.text}'),
        )
     ],
    );
  }

@override
  void dispose() {
    super.dispose();
    // 手动调用 controller 的 dispose 方法以释放资源
    editController.dispose();
  }
}

六、显示弹框

 RaisedButton(
          child: Text("click"),
          onPressed: () {
            showDialog(
                // 第一个 context 是参数名,第二个 context 是 State 的成员变量
                context: context,
                builder: (_) {
                return AlertDialog(
                    // dialog 的内容
                    content: Text(editController.text),
                    // actions 设置 dialog 的按钮
                    actions: [
                      FlatButton(
                        child: Text('OK'),
                        // 用户点击按钮后,关闭弹框
                        onPressed: () => Navigator.pop(context),
                      )
                    ],
                  );
               }
            );
          }
)

七、Container、Padding 、Center

Flutter的设计思想就是完全的widget化!连最基本的padding,Center都是widget。Container类似于android中的ViewGroup。

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   return Padding(
      padding: EdgeInsets.all(8.0),
      child: Text('text'),
   );
  }
}
class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   return Container(
      padding: EdgeInsets.all(8.0),
      margin: EdgeInsets.all(4.0),
      width: 200.0,
      height: 200.0,
      decoration: BoxDecoration(
        // 背景色
        color: Colors.grey,
        // 圆角
        borderRadius: BorderRadius.circular(5.0),
 ),

      // 把文本放在 Container 的中间
      child: Center(
          child: Text('text'),
      ),
    );
  }
}

八、水平布局Row、竖直布局Column

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      // 只有一个子元素的 widget,一般使用 child 参数来设置;Row 可以包含多个子控件,
      // 对应的则是 children
      children: [
        Text('text1'),
        Text('text2'),
        Text('text3'),
      ],
    );
  }
}

Column 的使用和Row是一样的

九、Expand 控件

见上面TextField 的例子。通过使用 Expand,TextField 才能够占满一行里除按钮外的所有空间。当一行/列里有多个 Expand 时,我们还可以通过设置它的 flex 参数,在多个 Expand 之间按比例划分可用空间。

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
    children: [
        Expanded(
          // 占一行的 2/3
          flex: 2,
          child: RaisedButton(child: Text('btn1'),),
        ),
        Expanded(
          // 占一行的 1/3
          flex: 1,
          child: RaisedButton(child: Text('btn2'),),
        ),
      ],
    );
  }
}

 Expanded 只能包含一个子元素,使用的参数名是 child

十、Stack 布局

有些时候,我们可能会希望一个控件叠在另一个控件的上面。于是,Stack 应运而生:

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
        children: [
        Text('foobar'),
        Text('barfoo'),
      ],
    );
  }
}

默认情况下,子控件都按 Stack 的左上角对齐,于是,上面的两个文本完全一上一下堆叠在一起。我们还可以通过设置 alignment 参数来改变这个对齐的位置:

class TestWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Stack(
      // Aligment 的取值范围为 [-1, 1],Stack 中心为 (0, 0),
      // 这里设置为 (-0.5, -0.5) 后,可以让文本对齐到 Container 的 1/4 处
      alignment: const Alignment(-0.5, -0.5),
      children: [
        Container(
          width: 200.0,
          height: 200.0,
          color: Colors.blue,
        ),
        Text('foobar'),
     ],
    );
  }
}

实际使用中Stack中的子Widgets分为两种:

  • positioned
    • 是包裹在组件Positioned中的组件
    • 可以通过Positioned属性灵活定位
  • non-positioned
    • 没有包裹在Positioned组件中
    • 需要通过父Widget Stack 的属性来控制布局
new Container(
            color: Colors.yellow,
            height: 150.0,
            width: 500.0,
            child: new Stack(children: [
              new Container(
                color: Colors.blueAccent,
                height: 50.0,
                width: 100.0,
                alignment: Alignment.center,
                child: Text('unPositioned'),
              ),
              new Positioned(
                  left: 40.0,
                  top: 80.0,
                  child: new Container(
                    color: Colors.pink,
                    height: 50.0,
                    width: 95.0,
                    alignment: Alignment.center,
                    child: Text('Positioned'),
                  )),
            ]))

Android Flutter:Dart语言(布局篇)_第4张图片

通过组合 Row/Column 和 Stack,已经能够完成绝大部分的布局了,所以 Flutter 里没有相对布局之类的东西。

十一、Visibility

在Flutter中,组件中没有visibility属性。visibility的控制还是比较麻烦的。目前有几种方法

1、删除法:

  • 单个组件‘隐藏’自己。在build方法中返回一个空的Container.
  • 多个child,在父容器的children字段的list中,删除掉对应的cell

2、Offstage的offstage属性设置为true

@override
Widget build(BuildContext context) {
  return new Offstage(
          offstage: !isVisible,
          child:child);
}

3、透明度

 设置widget的透明度,使之不可见。但依然会绘制,浪费计算资源,且占据的位置是存在的

十二、state 生命周期

  • initState插入渲染树时调用,只调用一次
  • didChangeDependenciesstate依赖的对象发生变化时调用
  • didUpdateWidget组件状态改变时候调用,可能会调用多次
  • build构建Widget时调用
  • deactivate当移除渲染树的时候调用
  • dispose组件即将销毁时调用

 

本篇文章大部分内容摘自:https://juejin.im/post/5bd54b7be51d456c430e35f6, https://juejin.im/post/5b8ce76f51882542c0626887  感谢!

 

 

你可能感兴趣的:(Android,Flutter)