美文网首页
Flutter布局---Container

Flutter布局---Container

作者: sun5kong | 来源:发表于2019-07-29 14:58 被阅读0次

    简介

    A convenience widget that combines common painting, positioning, and sizing widgets.

    Container 在Flutter中非常常见, 是一个结合绘制(painting), 定位(position)以及尺寸(sizing)的widget.

    组成

    Container的组成如下:

    • 最里层的是child元素;
    • child元素首先会被padding包着;
    • 然后添加额外的constraints限制;
    • 最后添加margin.

    Container的绘制的过程如下:

    • 首先会绘制transform效果;
    • 接着绘制decoration;
    • 后绘制child;
    • 最后绘制foregroundDecoration.

    Container自身尺寸的调节分两种情况:

    • Container在没有子节点(children)的时候,会试图去变得足够大。除非constraints是unbounded限制,在这种情况下,Container会试图去变得足够小。
    • 带子节点的Container,会根据子节点尺寸调节自身尺寸,但是Container构造器中如果包含了width、height以及constraints,则会按照构造器中的参数来进行尺寸的调节。
    源码解析

    构造函数如下:

    Container({
        Key key,
        this.alignment,
        this.padding,
        Color color,
        Decoration decoration,
        this.foregroundDecoration,
        double width,
        double height,
        BoxConstraints constraints,
        this.margin,
        this.transform,
        this.child,
      })
    

    属性解析

    key:Container唯一标识符,用于查找更新。

    alignment:控制child的对齐方式,如果container或者container父节点尺寸大于child的尺寸,这个属性设置会起作用,有很多种对齐方式。

    padding:decoration内部的空白区域,如果有child的话,child位于padding内部。padding与margin的不同之处在于,padding是包含在content内,而margin则是外部边界,设置点击事件的话,padding区域会响应,而margin区域不会响应。

    color:用来设置container背景色,如果foregroundDecoration设置的话,可能会遮盖color效果。

    decoration:绘制在child后面的装饰,设置了decoration的话,就不能设置color属性,否则会报错,此时应该在decoration中进行颜色的设置。

    foregroundDecoration:绘制在child前面的装饰。

    width:container的宽度,设置为double.infinity可以强制在宽度上撑满,不设置,则根据child和父节点两者一起布局。

    height:container的高度,设置为double.infinity可以强制在高度上撑满。

    constraints:添加到child上额外的约束条件。

    margin:围绕在decoration和child之外的空白区域,不属于内容区域。

    transform:设置container的变换矩阵,类型为Matrix4。

    child:container中的内容widget。

    源码
    decoration = decoration ?? (color != null ? new BoxDecoration(color: color) : null),
    

    可以看出, 对于颜色的设置,最后都是转换为decoration来进行绘制的。如果同时包含decoration和color两种属性,则会报错。

    @override
      Widget build(BuildContext context) {
        Widget current = child;
    
        if (child == null && (constraints == null || !constraints.isTight)) {
          current = new LimitedBox(
            maxWidth: 0.0,
            maxHeight: 0.0,
            child: new ConstrainedBox(constraints: const BoxConstraints.expand())
          );
        }
    
        if (alignment != null)
          current = new Align(alignment: alignment, child: current);
    
        final EdgeInsetsGeometry effectivePadding = _paddingIncludingDecoration;
        if (effectivePadding != null)
          current = new Padding(padding: effectivePadding, child: current);
    
        if (decoration != null)
          current = new DecoratedBox(decoration: decoration, child: current);
    
        if (foregroundDecoration != null) {
          current = new DecoratedBox(
            decoration: foregroundDecoration,
            position: DecorationPosition.foreground,
            child: current
          );
        }
    
        if (constraints != null)
          current = new ConstrainedBox(constraints: constraints, child: current);
    
        if (margin != null)
          current = new Padding(padding: margin, child: current);
    
        if (transform != null)
          current = new Transform(transform: transform, child: current);
    
        return current;
      }
    

    Container 的 build 函数的绘制过程是一个线形的判断过程, 一层层的包裹着Widget, 去实现不同的样式.

    示例
    void main() => runApp(MyApp());
    
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue
          ),
          home: MyHomePage(),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key}) : super(key: key);
      @override
      _MyHomePage createState() => _MyHomePage();
    }
    
    class _MyHomePage extends State<MyHomePage> {
    
      String textToShow = "I like Flutter";
    
      void _updateText(){
        print('点击');
        setState(() {
          textToShow = "Flutter is Awesome";
        });
        Navigator.push(
          context,
          new MaterialPageRoute(builder: (context) => new SamplePage())
        );
      }
      @override
      Widget build(BuildContext context) {
        // TODO: implement build
        return Scaffold(
          appBar: AppBar(
              title: Text("Sample App")
          ),
          body: new Container(
            constraints: new BoxConstraints.expand(
              height: Theme.of(context).textTheme.display1.fontSize * 1.1 + 200
            ),
            decoration: new BoxDecoration(
              border: new Border.all(width: 2.0, color: Colors.red),
              color: Colors.grey,
              borderRadius: new BorderRadius.all(new Radius.circular(20)),
              image: new DecorationImage(
                  image: new NetworkImage('http://h.hiphotos.baidu.com/zhidao/wh%3D450%2C600/sign=0d023672312ac65c67506e77cec29e27/9f2f070828381f30dea167bbad014c086e06f06c.jpg'),
                  centerSlice: new Rect.fromLTRB(270, 180, 1360, 730)
              ),
            ),
            padding: const EdgeInsets.all(8.0),
            alignment: Alignment.center,
            child: new Text(textToShow,
              style: Theme.of(context).textTheme.display1.copyWith(color: Colors.black),
            ),
            transform: new Matrix4.rotationZ(0.3),
          ),
          floatingActionButton: FloatingActionButton(
              onPressed: _updateText,
              tooltip: 'Update Text',
              child: Icon(Icons.update),
          ),
        );
      }
    }
    
    屏幕快照 2019-07-29 下午2.57.48.png
    使用场景
    • 需要设置间隔
    • 需要设置背景
    • 需要设置圆角或者边框
    • 需要对齐
    • 需要设置背景图片

    相关文章

      网友评论

          本文标题:Flutter布局---Container

          本文链接:https://www.haomeiwen.com/subject/jgybrctx.html