布局

若想将文字置于当前页面的中心方位,能够运用Center或许Alignment控件

Center

class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return const Center(
        child: Text('LayoutDemo', style:TextStyle(fontSize: 20, color: Colors.red, backgroundColor: Colors.cyan))
    );
  }
}

Simulator Screen Shot - iPhone 13 Pro Max - 2022-11-13 at 01.24.11.png

Alignment

运用Container包装一层,设置子控件的成员变量Alignment

class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      alignment: const Alignment(0, 0),
      child: const Text('LayoutDemo', style:TextStyle(fontSize: 20, backgroundColor: Colors.cyan))
    );
  }
}

Simulator Screen Shot - iPhone 13 Pro Max - 2022-11-13 at 01.29.39.png

经过调试Alignment(x, y)可知坐标系如下图,原点位于中心方位,xy的取值范围均为[-1,1]
image.png

布局

Flutter中的布局与前端中的布局方式很类似,都是FlexBox形式,下面别离介绍横向布局纵向布局层级布局

Row(横向布局)

运用Row(横向布局)布局的控件会在横轴方向占满父部件

留意这个特点mainAxisAlignment(主轴方向布局)共有以下几个选项:

  • start:布局从主轴开端的方位正向布局
  • end:布局从主轴完毕的方位开端反向布局
  • center:布局位于主轴中心的方位
  • spaceBetween:把主轴方向剩余的空间均匀的散布于控件之间
  • spaceAround:把主轴方向剩余的空间平均分配到空间周围
  • spaceEvenly:把主轴发现剩余的空间平均分配在控件周围空余的部分
class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      alignment: const Alignment(0, 0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        children: [
          Container(
            color: Colors.red,
            width: 50,
            height: 50,
            child: cosnt Icon(Icons.add),
          ),
          Container(
            color: Colors.blue,
            width: 50,
            height: 50,
            child: cosnt Icon(Icons.search),
          ),
          Container(
            color: Colors.white,
            width: 50,
            height: 50,
            child: cosnt Icon(Icons.battery_alert),
          ),
        ],
      )
    );
  }
}

mainAxisAlignment

start

布局沿主轴开端的方向,刚才现已论述过这儿的坐标系,又是Row摆放,则主轴是x方向,从左至右

image.png

end

布局沿主轴完毕的方向,所以是从右至左来排布

image.png

center

布局位于主轴中心的方位

image.png

spaceBetween

把主轴方向剩余的空间均匀的散布于控件之间

image.png

spaceAround

把主轴方向剩余的空间平均分配到空间周围

image.png

spaceEvenly

把主轴发现剩余的空间平均分配在控件周围空余的部分

image.png

crossAxisAlignment

这儿举例仍然是在Row(横向布局)的状况下来讨论crossAxisAlignment特点

crossAxisAlignment中有以下几个选项:

  • start:向穿插轴开端的方向对齐
  • end:向穿插轴完毕的方向对齐
  • center:穿插轴方向居中对齐
  • stretch:填满穿插轴方向
  • baseline:文字基线对齐
class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      alignment: const Alignment(0, 0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Container(
            color: Colors.red,
            child: const Icon(Icons.add, size: 50),
          ),
          Container(
            color: Colors.blue,
            child: const Icon(Icons.search, size: 100),
          ),
          Container(
            color: Colors.white,
            child: const Icon(Icons.battery_alert, size: 150),
          ),
        ],
      )
    );
  }
}

start

在穿插轴方向从上到下进行布局,相当于顶部对齐
image.png

end

在穿插轴方向从下到上进行布局,相当于底部对齐

image.png

center

在穿插轴方向上居中布局,这也是默许特点

image.png

stretch

子控件将撑满穿插轴方向

image.png

baseline

baseline要配合文字来进行演示,一起也需求设置textBaseline,意思就是以文字的基线来进行对齐

class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      alignment: const Alignment(0, 0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.baseline,
        textBaseline: TextBaseline.alphabetic,
        children: [
          Container(
            height: 80,
            color: Colors.red,
            child: const Text('好好学习', style: TextStyle(fontSize: 15))
          ),
          Container(
            height: 80,
            color: Colors.blue,
            child: const Text('天天要吃饭', style: TextStyle(fontSize: 30))
          ),
          Container(
            height: 80,
            color: Colors.white,
            child: const Text('晚上', style: TextStyle(fontSize: 60))
          ),
        ],
      )
    );
  }
}

image.png

Expanded(填充布局)

Expanded(填充布局):

  • 在主轴方向不会剩余间隙,将被Expanded包装的部件进行拉伸和紧缩
  • 主轴横向,设置宽度没有意义
  • 主轴纵向,设置高度没有意义
  • TextExpanded包装后文字能够自动换行,所以Expanded也被称为灵活布局
class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    // return const Center(
    //     child: Text('LayoutDemo', style:TextStyle(fontSize: 20, color: Colors.red, backgroundColor: Colors.cyan))
    // );
    return Container(
      color: Colors.orange,
      alignment: const Alignment(0, 0),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.end,
        crossAxisAlignment: CrossAxisAlignment.baseline,
        textBaseline: TextBaseline.alphabetic,
        children: [
          Expanded(child: Container(
              height: 80,
              color: Colors.red,
              child: const Text('好好学习', style: TextStyle(fontSize: 15))
          )),
          Expanded(child: Container(
              height: 80,
              color: Colors.blue,
              child: const Text('天天要吃饭', style: TextStyle(fontSize: 30))
          )),
          Expanded(child: Container(
              height: 80,
              color: Colors.white,
              child: const Text('晚上', style: TextStyle(fontSize: 60))
          ))
        ],
      )
      //child: const Text('LayoutDemo', style:TextStyle(fontSize: 20, backgroundColor: Colors.cyan))
    );
  }
}

image.png

Column(纵向布局)

Row相同,运用Column(纵向布局)布局的控件会在纵轴方向占满父部件,mainAxisAlignmentcrossAxisAlignment特点同上,这儿不再演示

class LayoutDemo extends StatelessWidget {
  const LayoutDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.orange,
      alignment: const Alignment(0, 0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.end,
        // textBaseline: TextBaseline.alphabetic,
        children: [
          Expanded(child: Container(
              height: 80,
              color: Colors.red,
              child: const Text('好好学习', style: TextStyle(fontSize: 15))
          )),
          Expanded(child: Container(
              height: 80,
              color: Colors.blue,
              child: const Text('天天要吃饭', style: TextStyle(fontSize: 30))
          )),
          Expanded(child: Container(
              height: 80,
              color: Colors.white,
              child: const Text('晚上', style: TextStyle(fontSize: 60))
          ))
        ],
      )
    );
  }
}

Stack(层次布局)

class StackDemo extends StatelessWidget {
  const StackDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: const Alignment(-1,-1),
      children: [
        Container(
          color: Colors.white,
          width: 200,
          height: 200,
          child: const Icon(Icons.add)
        ),
        Container(
            color: Colors.blue,
            width: 100,
            height: 100,
            child: const Icon(Icons.search)
        ),Container(
            color: Colors.cyan,
            width: 50,
            height: 50,
            child: const Icon(Icons.alarm)
        ),
      ],
    );
  }
}

image.png

Stack也叫层次布局,如果这儿需求子控件一个在左一个在右的话则需求运用到Stack中的Positioned特点来完结控制子控件的相对方位

class StackDemo extends StatelessWidget {
  const StackDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Stack(
      alignment: const Alignment(-1,-1),
      children: [
        Positioned(child: Container(
            color: Colors.white,
            width: 200,
            height: 200,
            child: const Icon(Icons.add)
        )),
        Positioned(
            left: 1,
            bottom: 1,
            child: Container(
            color: Colors.blue,
            width: 100,
            height: 100,
            child: const Icon(Icons.search)
        )),
        Positioned(
            right: 1,
            child:  Container(
            color: Colors.cyan,
            width: 50,
            height: 50,
            child: const Icon(Icons.alarm)
        ))
      ],
    );
  }
}

image.png

AspectRatio(设置宽高比)

class AspectRatioDemo extends StatelessWidget {
  const AspectRatioDemo({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Container(
      //padding: const EdgeInsets.all(10),
      color: Colors.blue,
      //width: 400,
      height: 150,
      child: AspectRatio(
        aspectRatio: 2/1,
        child: Container(
          alignment: const Alignment(0,0),
          color: Colors.red,
        ),
      ),
    );
  }
}

经过设置aspectRatio(宽高比)2/1来设置宽度为300,如果父控件中设置了宽度,则以父控件为主

image.png

状况办理

现在需求是如果有数据改动了需求实时烘托到页面上以便看到改动,举例如下

class StateManageDemo extends StatelessWidget {
  StateManageDemo({Key? key}) : super(key: key);
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('StateManageDemo', style: TextStyle(fontSize: 15),)),
      body: Center(
        child: Chip(
          label: Text('$count'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: (){
          count++;
          debugPrint('count = $count');
        },
      ),
    );
  }
}

image.png

可是运行后发现,每次点击按钮后的确现已改动了count的值,可是并未更新到页面上,甚至热更新也不能更新成果上去。原因是StatelessWidget是一个无状况的控件,也就是说在创立完结后就不会再进入其build办法了,那么也就无法完结更新,所以如果想运用数据有改动的控件能够运用StatefullWidget

class StateManageDemo extends StatefulWidget {
  const StateManageDemo({Key? key}) : super(key: key);
  @override
  State<StatefulWidget> createState() => _SMDState();
}
class _SMDState extends State<StateManageDemo>{
  int count = 0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('StateManageDemo', style: TextStyle(fontSize: 15),)),
      body: Center(
        child: Chip(
          label: Text('$count'),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: const Icon(Icons.add),
        onPressed: (){
          count++;
          setState(() {
          });
          debugPrint('count = $count');
        },
      ),
    );
  }
}

运用StatefullWidget控件时需求搭配运用一个状况办理的类,本来的build办法放在这个类中实现,也就是说数据由这个类来办理和烘托,并且在状况改动后需求设置回调setState,这样就能够完结上面的需求了。