九、大话Flutter——容器类组件

124 阅读4分钟

一、Padding

Padding通常用于设置子Widget到父Widget的边距(你可以称之为是父组件的内边距或子Widget的外边距)

Padding({
  ...
  EdgeInsetsGeometry padding,
  Widget child,
})

EdgeInsetsGeometry是一个抽象类,开发中,我们一般都使用EdgeInsets类,它是EdgeInsetsGeometry的一个子类,定义了一些设置填充的便捷方法。

二、EdgeInsets

EdgeInsets提供的便捷方法:

  • fromLTRB(double left, double top, double right, double bottom):分别指定四个方向的填充。
  • all(double value) : 所有方向均使用相同数值的填充。
  • only({left, top, right ,bottom }):可以设置具体某个方向的填充(可以同时指定多个方向)。
  • symmetric({ vertical, horizontal }):用于设置对称方向的填充,verticaltopbottomhorizontalleftright
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
  const TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("容器组件"),
          backgroundColor: Colors.red,
          
        ),
        body:Column(
          children: [
            Padding(
                // 左边添加8像素
                padding: EdgeInsets.only(left: 8),
              child: Text('Hello world'),
            ),
            Padding(
                // 上下添加8像素
                padding: EdgeInsets.symmetric(vertical: 8),
              child: Text('Hello world'),
            ),
            Padding(
               // 四个方向添加
              padding: EdgeInsets.fromLTRB(10, 10, 10, 10),
              child: Text('Hello world'),
            )
            
          ],

        ),
        
      ),
      
    );

  }
}
图片.png

三、BoxDecoration(装饰器)

BoxDecoration类,它是一个Decoration的子类(Decoration类型是一个抽象类),实现了常用的装饰元素的绘制。

BoxDecoration常见属性:

const BoxDecoration({  
this.color, // 颜色,会和Container中的color属性冲突  
this.image, // 背景图片  
this.border, // 边框,对应类型是Border类型,里面每一个边框使用BorderSide  
this.borderRadius, // 圆角效果  
this.boxShadow, // 阴影效果  
this.gradient, // 渐变效果  
this.backgroundBlendMode, // 背景混合  
this.shape = BoxShape.rectangle, // 形变  
})
import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
  const TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("容器组件"),
          backgroundColor: Colors.red,
          
        ),
        body:Center(
          child: Container(
            width: 150,
            height: 150,
            child: Icon(Icons.pets,size: 32,color: Colors.white,),
            decoration: BoxDecoration(
              color: Colors.red,
              //边框
              border: Border.all(
                color: Colors.orange,
                width: 10,
                style: BorderStyle.solid,
              ),
              // 圆角,
              borderRadius: BorderRadius.circular(20), // 这里也可以使用.only分别设置
            ),
          ),
        ),
        
      ),
      
    );

  }
}
图片.png

四、 DecoratedBox(装饰容器)

DecoratedBox可以在其子组件绘制前(或后)绘制一些装饰(Decoration),如背景、边框、渐变等。DecoratedBox定义如下:

const DecoratedBox({
  Decoration decoration,
  DecorationPosition position = DecorationPosition.background,
  Widget? child
})
  • decoration:代表将要绘制的装饰,它的类型为DecorationDecoration是一个抽象类,它定义了一个接口 createBoxPainter(),子类的主要职责是需要通过实现它来创建一个画笔,该画笔用于绘制装饰。

  • position:此属性决定在哪里绘制Decoration,它接收DecorationPosition的枚举类型,该枚举类有两个值:

    • background:在子组件之后绘制,即背景装饰。

    • foreground:在子组件之上绘制,即前景。

例: 实现一个带阴影的背景色渐变的按钮:

import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
 const TestPage({super.key});

 @override
 Widget build(BuildContext context) {
   return MaterialApp(
     home: Scaffold(
       appBar: AppBar(
         title: Text("容器组件"),
         backgroundColor: Colors.red,
         
       ),
       body:Center(
         child: DecoratedBox(
             decoration: BoxDecoration(
               // 背景渐变
               gradient: LinearGradient(colors: [Colors.red,Colors.orange.shade700]),
               // 圆角
               borderRadius: BorderRadius.circular(10),
               boxShadow: [
                 BoxShadow(
                   color: Colors.black54,
                   offset: Offset(2.0, 2.0),
                   blurRadius: 4.0
                 ),
               ],
             ),
           child: Padding(
               padding: EdgeInsets.symmetric(horizontal: 80,vertical: 20),
             child: Text("Login",style: TextStyle(color: Colors.white,fontSize: 20),),
           ),
         )
       ),
       
     ),
     
   );

 }
}
图片.png

五、 Container(容器组件)

Container组件类似于Android中的View,iOS中的UIView。

如果你需要一个视图,有一个背景颜色、图像、有固定的尺寸、需要一个边框、圆角等效果,那么就可以使用Container组件。

Container是一个组合类容器,它本身不对应具体的RenderObject,它是DecoratedBoxConstrainedBox、TransformPaddingAlign等组件组合的一个多功能容器,所以我们只需通过一个Container组件可以实现同时需要装饰、变换、限制的场景。下面是Container的定义:

Container({
  this.alignment,
  this.padding, //容器内补白,属于decoration的装饰范围
  Color color, // 背景色
  Decoration decoration, // 背景装饰
  Decoration foregroundDecoration, //前景装饰
  double width,//容器的宽度
  double height, //容器的高度
  BoxConstraints constraints, //容器大小的限制条件
  this.margin,//容器外补白,不属于decoration的装饰范围
  this.transform, //变换
  this.child,
  ...
})

Container的大多数属性在介绍其他容器时都已经介绍过了,不再赘述,但有两点需要说明:

  • 容器的大小可以通过widthheight属性来指定,也可以通过constraints来指定;如果它们同时存在时,widthheight优先。实际上Container内部会根据widthheight来生成一个constraints
  • colordecoration是互斥的,如果同时设置它们则会报错!实际上,当指定color时,Container内会自动创建一个decoration

import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
  const TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("容器组件"),
          backgroundColor: Colors.red,
          
        ),
        body:Center(
          child:Container(
            color: Colors.red,
            width: 100,
            height: 100,
            child: Icon(Icons.pets,size: 32,color: Colors.white,),
          ),
        ),
        
      ),
      
    );

  }
}

六、Container组件中的marginpadding

接下来我们来研究一下Container组件marginpadding属性的区别:

import 'package:flutter/material.dart';
class TestPage extends StatelessWidget {
  const TestPage({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text("容器组件"),
          backgroundColor: Colors.red,
          
        ),
        body:Column(
          children: [
            Container(
              margin: EdgeInsets.all(20),
              color: Colors.orange,
              child: Text("Hello word!"),
            ),

            Container(
              padding: EdgeInsets.all(20),
              color: Colors.orange,
              child: Text("Hello word!"),
            )

          ],
        ),
        
      ),
      
    );

  }
}
图片.png

可以发现,直观的感觉就是margin的留白是在容器外部,而padding的留白是在容器内部,读者需要记住这个差异。事实上,Containermarginpadding都是通过Padding 组件来实现的,上面的示例代码实际上等价于:

...
Padding(
  padding: EdgeInsets.all(20.0),
  child: DecoratedBox(
    decoration: BoxDecoration(color: Colors.orange),
    child: Text("Hello world!"),
  ),
),
DecoratedBox(
  decoration: BoxDecoration(color: Colors.orange),
  child: Padding(
    padding: const EdgeInsets.all(20.0),
    child: Text("Hello world!"),
  ),
),
...