likes
comments
collection
share

Flutter中的布局&状态管理

作者站长头像
站长
· 阅读数 41

布局

若想将文字置于当前页面的中间位置,可以使用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))
    );
  }
}

Flutter中的布局&状态管理

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))
    );

  }
}

Flutter中的布局&状态管理

通过调试Alignment(x, y)可知坐标系如下图,原点位于中心位置,xy的取值范围均为[-1,1] Flutter中的布局&状态管理

布局

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方向,从左至右

Flutter中的布局&状态管理

end

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

Flutter中的布局&状态管理

center

布局位于主轴中心的位置

Flutter中的布局&状态管理

spaceBetween

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

Flutter中的布局&状态管理

spaceAround

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

Flutter中的布局&状态管理

spaceEvenly

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

Flutter中的布局&状态管理

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

在交叉轴方向从上到下进行布局,相当于顶部对齐 Flutter中的布局&状态管理

end

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

Flutter中的布局&状态管理

center

在交叉轴方向上居中布局,这也是默认属性

Flutter中的布局&状态管理

stretch

子控件将撑满交叉轴方向

Flutter中的布局&状态管理

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))
          ),
        ],
      )
    );

  }
}

Flutter中的布局&状态管理

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))
    );

  }
}

Flutter中的布局&状态管理

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)
        ),
      ],
    );
  }
}

Flutter中的布局&状态管理

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)
        ))

      ],
    );
  }
}

Flutter中的布局&状态管理

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,如果父控件中设置了宽度,则以父控件为主

Flutter中的布局&状态管理

状态管理

现在需要是如果有数据变化了需要实时渲染到页面上以便看到变化,举例如下

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');
        },
      ),
    );
  }
}

Flutter中的布局&状态管理

但是运行后发现,每次点击按钮后确实已经改变了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,这样就可以完成上面的需求了。

转载自:https://juejin.cn/post/7165498144245940261
评论
请登录