美文网首页美文共赏Flutter初见
Flutter-flutter基础之组件基础(八)

Flutter-flutter基础之组件基础(八)

作者: 陌问MW | 来源:发表于2020-05-06 21:09 被阅读0次

一、Stack Widget

Stack Widget 可以用来设置多个子 Widget ,这些子 Widget 以堆叠的方式进行排列。Stack 的子 Widget 可以分为已定位和未定位,定位使用 Positioned Widget 配合 Stack 一起使用。Stack 本身的大小将包含所有未定位的子 Widget ,这些子 Widget 根据对齐方式定位(在从左到右的环境中,默认为左上角,在从右到左的环境中,默认为右上角)。然后根据已定位的子 Widget 的上、右、下、左的属性相对于 Stack 放置它们。

Stack 的构造方法如下:

Stack({
  Key key,
  //AlignmentGeometry类型可选命名参数,如何对齐Stack中未定位和部分定位的子Widget
  //使用AlignmentDirectional
  this.alignment = AlignmentDirectional.topStart,
  //TextDirection类型可选命名参数,文本对齐方向设置
  this.textDirection,
  //StackFit类型可选命名参数,如何调整Stack中未定位的子Widget
  this.fit = StackFit.loose,
  //Overflow类型可选命名参数,设置溢出部分如何剪裁
  this.overflow = Overflow.clip,
  //List<Widget>类型可选命名参数,要显示的Widget
  List<Widget> children = const <Widget>[],
})

AlignmentDirectional 用于设置如何对齐 Stack 中未定位和部分定位的子 Widget 。对于未定位的子 Widget 项彼此相对放置,以使通过对齐确定的点位于同一位置。部分定位的子 Widget 指的是未在特定轴上指定对齐方式的子 Widget ,使用对齐方式来确定应如何在未指定的轴上定位它们。AlignmentDirectional 的构造方法如下:

//两个参数均为double类型
const AlignmentDirectional(this.start, this.y)

可以使用构造方法设置,也可以直接使用提供好的位置静态属性,如下:

/// The top corner on the "start" side.
static const AlignmentDirectional topStart = AlignmentDirectional(-1.0, -1.0);
/// The center point along the top edge.
///
/// Consider using [Alignment.topCenter] instead, as it does not need
/// to be [resolve]d to be used.
static const AlignmentDirectional topCenter = AlignmentDirectional(0.0, -1.0);
/// The top corner on the "end" side.
static const AlignmentDirectional topEnd = AlignmentDirectional(1.0, -1.0);
/// The center point along the "start" edge.
static const AlignmentDirectional centerStart = AlignmentDirectional(-1.0, 0.0);
/// The center point, both horizontally and vertically.
///
/// Consider using [Alignment.center] instead, as it does not need to
/// be [resolve]d to be used.
static const AlignmentDirectional center = AlignmentDirectional(0.0, 0.0);
/// The center point along the "end" edge.
static const AlignmentDirectional centerEnd = AlignmentDirectional(1.0, 0.0);
/// The bottom corner on the "start" side.
static const AlignmentDirectional bottomStart = AlignmentDirectional(-1.0, 1.0);
/// The center point along the bottom edge.
///
/// Consider using [Alignment.bottomCenter] instead, as it does not
/// need to be [resolve]d to be used.
static const AlignmentDirectional bottomCenter = AlignmentDirectional(0.0, 1.0);
/// The bottom corner on the "end" side.
static const AlignmentDirectional bottomEnd = AlignmentDirectional(1.0, 1.0);

位置属性简单易懂,不做中文说明了。AlignmentDirectional 的设置与 TextDirection 是关系的,对于不同的环境方向,AlignmentDirectional 的起始位置也不同。

StackFit 用于设置如何调整Stack中未定位的子 Widget ,其是一个枚举类型值,如下:

enum StackFit {
  //从其父级传递到Stack的约束被放宽了
  //例如:如果Stack具有强制其为350x600的约束,那么这将允许Stack的未定位子Widget
  //具有从0到350的任何宽度和从0到600的任何高度
  loose,

  //从其父级传递到Stack的约束被收紧到允许的最大大小。
  //例如:如果Stack具有宽度在10到100范围内、高度在0到600范围内的松散约束,则Stack中未
  //定位的子级的大小都将为100像素宽、600像素高
  expand,

  //从其父级传递到Stack的约束未修改地传递到未定位的子级
  //例如:如果Stack是行的扩展子级,则水平约束将是紧的,而垂直约束将是松的
  passthrough,
}

Stack 的使用方式如下:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        width: 500,
        height: 200,
        color: Colors.yellow,
        child:Stack(              //Stack
          alignment: AlignmentDirectional.topStart,
          textDirection: TextDirection.ltr,
          fit: StackFit.loose,
          overflow: Overflow.clip,
          children: <Widget>[
            Image.network("http://www.mwpush.com/uploads/avatar.png"),
            Text("Stack1", style: TextStyle(color: Colors.blue, fontSize: 30),),
            Text("Stack2",style: TextStyle(color: Colors.red, fontSize: 20),),
          ],
        ),
      ),
    );
  }
}

效果如下:


2020324102.jpg

定位 Widget 使用 Positioned ,用于控制 Stack 的子 Widget 的位置。如果一个 Widget 包装在 Positioned 中,那么这个 Widget 就是 Stack 中的一个定位 Widget 。如果单独设置 top 则表示该子 Widget 距离 Stack 顶部的距离,同时设定 topbottom 则子 Widget 会根据设置调整子 Widget 的高度以使其满足顶部和底部的距离,左右也是一样。其中 topbottomheight 只能同时设置其中的两项,另外一项必须为空,如果都为空,则使用 Stackalignment 在垂直方向进行定位。 leftrightwidth 也只能设置其中两项,另外一项必须为空,如果所有都为空,则使用 Stackalignment 在水平方向进行定位。

Positioned 的构造方法如下:

const Positioned({
  Key key,
  //double类型可选命名参数,子Widget底部距离Stack左边的距离
  this.left,
  //double类型可选命名参数,子Widget底部距离Stack顶部的距离
  this.top,
  //double类型可选命名参数,子Widget底部距离Stack右边的距离
  this.right,
  //double类型可选命名参数,子Widget底部距离Stack底部的距离
  this.bottom,
  //double类型可选命名参数,子Widget的宽度
  this.width,
  //double类型可选命名参数,子Widget的高度
  this.height,
  //Widget类型必传参数,要显示的Widget
  @required Widget child,
})

使用方法如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        width: 500,
        height: 200,
        color: Colors.yellow,
        child:Stack(              //Stack
          alignment: AlignmentDirectional.topStart,
          textDirection: TextDirection.ltr,
          fit: StackFit.loose,
          overflow: Overflow.clip,
          children: <Widget>[
            Image.network("http://www.mwpush.com/uploads/avatar.png"),
            Positioned(             //Positioned
              bottom: 10,
              top: 20,
              left: 120,
              width: 100,
              child: Container(child: Text("Stack1", style: TextStyle(color: Colors.blue, fontSize: 30,), ), color: Colors.red,),
            ),
            Text("Stack2",style: TextStyle(color: Colors.red, fontSize: 20),),
          ],
        ),
      ),
    );
  }
}

效果如下:


2020324208.jpg

二、IndexedStack Widget

Stack 可以显示一组 Widget ,IndexedStack 继承自 Stack ,用于选择性的只显示一组 Widget 中的一个。要显示的 Widget 通过 index 索引设置,编号从 0 开始。IndexedStack 的大小总是和一组 Widget 中的最大的 Widget 一样大。构造方法如下:

IndexedStack({
  Key key,
  //AlignmentGeometry类型可选命名参数,如何对齐Stack中未定位和部分定位的子Widget
  //使用AlignmentDirectional
  AlignmentGeometry alignment = AlignmentDirectional.topStart,
  //TextDirection类型可选命名参数,文本对齐方向设置
  TextDirection textDirection,
  //StackFit类型可选命名参数,如何调整Stack中未定位的子Widget
  StackFit sizing = StackFit.loose,
  //int类型可选参数,要显示的Widget
  this.index = 0,
  //List<Widget>类型可选命名参数,要显示的Widget
  List<Widget> children = const <Widget>[],
}) 

IndexedStack 只比 Stack 多了一个 index 属性,其他属性相同,默认显示 Widget 列中的第一个 Widget ,下标为 0 。IndexedStack 使用如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        width: 500,
        height: 200,
        color: Colors.yellow,
        child:IndexedStack(              //IndexedStack
          alignment: AlignmentDirectional.topStart,
          textDirection: TextDirection.ltr,
          sizing: StackFit.loose,
          index: 2,       //要显示的Widget的下标
          children: <Widget>[
            Image.network("http://www.mwpush.com/uploads/avatar.png"),
            Positioned(
              bottom: 10,
              top: 20,
              left: 120,
              width: 100,
              child: Container(child: Text("Stack1", style: TextStyle(color: Colors.blue, fontSize: 30,), ), color: Colors.red,),
            ),
            Text("Stack2",style: TextStyle(color: Colors.red, fontSize: 20),),
          ],
        ),
      ),
    );
  }
}

三、SizedBox Widget

SizedBox 是设置固定尺寸的 Widget ,如果设置了宽高,则子 Widget 会被强制为 SizedBox 的尺寸,如果不设置宽高,则 SizedBox 的尺寸将与子 Widget 相同。 如果没有给定子 Widget ,SizedBox 将尝试在给定父对象约束的情况下,将自身的大小调整到尽可能接近指定的高度和宽度。如果高度或宽度为空或未指定,将被视为零。

有以下几个构造方法:

//创建固定尺寸的SizedBox,宽高可以为空,此时表示大小不受限制
const SizedBox({
  Key key, 
  //double类型可选命名参数,设置SizedBox的宽度,子Widget也会具有此宽度
  this.width, 
  //double类型可选命名参数,设置SizedBox的高度,子Widget也会具有此高度
  this.height, 
  //Widget类型可选命名参数,要显示的Widget
  Widget child
})
  
//创建一个将变得与其父级允许一样大的SizedBox,等效于将width和height设置为double.infinity
const SizedBox.expand({
  Key key, 
  //Widget类型可选命名参数,要显示的Widget
  Widget child 
})
 
//创建一个将变得尽可能小的SizeBox
const SizedBox.shrink({ 
  Key key, 
  //Widget类型可选命名参数,要显示的Widget
  Widget child 
})

//创建一个指定尺寸的SizeBox
SizedBox.fromSize({ 
  Key key, 
  //Widget类型可选命名参数,要显示的Widget
  Widget child, 
  //Size类型可选命名参数,设置SizedBox的尺寸,子Widget也具有此尺寸
  Size size
})

使用如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: SizedBox(
          height: 100,
          width: 300,
          child: Container(
            color: Colors.red,
            width: 10,
            height: 20,
          ),
      ),
    );
  }
}

这里的子 Widget 是 Container ,虽然 Container 也设置了宽高,但是没有生效,其宽高与 SizedBox 相同。但是如果子 Widget 不能设置宽高属性,则子 Widget 的大小不会与 SizedBox 设置的相同,但是会受其最大尺寸约束。上述代码效果如下:

2020324330.jpg

四、Flex Widget

Flex 使用一维数组来设置一组子 Widget ,其可以通过设置主轴的方向来控制水平或垂直显示 Widget ,它是上篇文章中介绍过的 RowColumn 的父类。如果在使用前已知要显示的 Widget 的方向,应考虑使用 RowColumn

Flex 是一个不可以滚动的 Widget ,当要显示的 Widget 超过可用范围则会抛出异常。其构造方法如下:

Flex({
  Key key,
  //Axis类型必传参数,设置主轴的方向(垂直或者水平),不设置会抛出异常
  @required this.direction,
  //MainAxisAlignment类型可选命名参数,如何沿着主轴放置子Widget
  this.mainAxisAlignment = MainAxisAlignment.start,
  //MainAxisSize类型可选命名参数,主轴上应占用多少空间,该值传入最大化还是最小化可用空间
  this.mainAxisSize = MainAxisSize.max,
  //CrossAxisAlignment类型可选命名参数,如何沿着次轴放置子Widget
  this.crossAxisAlignment = CrossAxisAlignment.center,
  //TextDirection类型可选命名参数,设置子Widget横向的排列方向,默认为环境方向
  this.textDirection,
  //VerticalDirection类型可选命名参数,设置子Widget纵向的排列顺序以及如何解释垂直方向的开始和结束
  this.verticalDirection = VerticalDirection.down,
  //TextBaseline类型可选命名参数,果根据基线对齐项目,使用哪个基线
  this.textBaseline,
  //List<Widget>类型可选命名参数,要显示的Widgets
  List<Widget> children = const <Widget>[],
})

Axis 用于设置主轴的方向,即要显示的 Widgets 的排列方向,是一个枚举类型值,如下:

enum Axis {
  //水平排列
  horizontal,
  //垂直排列
  vertical,
}

其他属性在上一篇文章做过说明,可查看上篇文章的 Row 部分。 Flex 的使用方式如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Flex(
        direction: Axis.horizontal,
        children: <Widget>[
          Text("Text1"),
          Text("Text2"),
          Text("Text3"),
          Text("Text4"),
          Text("Text5"),
        ],
      ),
    );
  }
}

五、Expanded Widget

Expanded 是用来扩展 RowColumnFlex 的子 Widget ,其作用是按一定比例填充子 Widgets 间的可用空间。如果要扩展多个 Widget ,可以通过设置扩展因子在可用空间进行空间分配。其构造方法如下:

const Expanded({
  Key key,
  //int类型可选命名参数,扩展因子  
  int flex = 1,
  //Widget类型必传参数,要显示的Widget 
  @required Widget child,  
})

使用如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Flex(
        direction: Axis.horizontal,
        children: <Widget>[
          Expanded(
            child: Container(child: Text("Text1"), color: Colors.red, height: 50,),
            flex: 1,
          ),
          Expanded(
            child: Container(child: Text("Text2"), color: Colors.blue, height: 50,),
            flex: 2,
          ),
          Expanded(
            child: Container(child: Text("Text3"), color: Colors.yellow, height: 50,),
            flex: 3,
          ),
        ],
      ),
    );
  }
}

效果如下:


2020324508.jpg

上面的代码中设置了扩展因子,是倍数关系,所以显示的结果宽度也是倍数关系,如果是垂直排列 Widget ,则高度是倍数关系。不设置扩展因子则子 Widget 会平均分配可用空间。也可以单独设置某个子 Widget 的扩展因子。

六、Wrap Widget

Wrap 也可以显示多个子 Widget ,其可以设置排列方向(水平或者垂直)显示 Widgets ,与 RowColumn 的不同之处在于,RowColumn 在可用空间无法显示全部 Widget 时会抛出异常,而 Warp 显示不下时会自动换行。

构造方法如下:

Wrap({
  Key key,
  //Axis类型可选命名参数,设置主轴的方向(垂直或者水平)
  this.direction = Axis.horizontal,
  //WrapAlignment类型可选命名参数,在主轴上如何排列子Widgets
  this.alignment = WrapAlignment.start,
  //double类型可选命名参数,主轴上排列的每个Widget之间的间隙
  this.spacing = 0.0,
  //WrapAlignment类型可选命名参数,!!!没有整明白此参数的作用,使用也没有看到效果
  this.runAlignment = WrapAlignment.start,
  //double类型可选命名参数,如果是横向排列则是每行之间的间距,纵向排列则是每列之间的间距
  this.runSpacing = 0.0,
  //WrapCrossAlignment类型可选命名参数,如何沿着次轴放置子Widget
  this.crossAxisAlignment = WrapCrossAlignment.start,
  //TextDirection类型可选命名参数,设置子Widget横向的排列方向,默认为环境方向
  this.textDirection,
  //VerticalDirection类型可选命名参数,设置子Widget纵向的排列顺序以及如何解释垂直方向的开始和结束
  this.verticalDirection = VerticalDirection.down,
  //List<Widget>类型可选命名参数,要显示的Widgets
  List<Widget> children = const <Widget>[],
})

使用如下

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        color: Colors.amber,
        child: Wrap(                        //Wrap
          direction: Axis.horizontal,
          textDirection: TextDirection.ltr,
          alignment: WrapAlignment.center,
          crossAxisAlignment: WrapCrossAlignment.end,
          spacing: 10,
          runSpacing: 20,
          runAlignment: WrapAlignment.center,

          children: <Widget>[
            Container(child: Text("Text1"), color: Colors.red, height: 100, width: 50,),
            Container(child: Text("Text2"), color: Colors.red, height: 50, width: 100,),
            Container(child: Text("Text3"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text4"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text5"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text6"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text7"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text8"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text9"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text10"), color: Colors.red, height: 50, width: 50,),
            Container(child: Text("Text11"), color: Colors.red, height: 30, width: 120,),
          ],
        ),
      )
    );
  }
}

效果如下:


2020325953.jpg

七、FittedBox Widget

FittedBox 用于管理子 Widget 在其父级 Widget 如何对齐和缩放。构造方法如下:

const FittedBox({
  Key key,
  //BoxFit类型可选命名参数,如何适配子Widget
  this.fit = BoxFit.contain,
  //AlignmentGeometry类型可选命名参数,如何在父级范围内对齐子Widget,使用Alignment
  this.alignment = Alignment.center,
  //Widget类型可选命名参数,要显示的Widget
  Widget child,
})

使用如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        color: Colors.yellow,
        height: 200,
        width: 400,
        child: FittedBox(
          fit: BoxFit.fitHeight,
          alignment: Alignment.topLeft,
          child: Container(
            height: 100,
            width: 100,
            color: Colors.red,
            child: Image.network("http://www.mwpush.com/uploads/avatar.png"),
          ),
        ),
      )
    );
  }
}

BoxFit 的设置和样式可以查看官网,地址为:https://api.flutter.dev/flutter/painting/BoxFit-class.html

上述代码效果如下:


20203241037.jpg

八、OverflowBox Widget

通常,当一个子 Widget 在 父 Widget 中时,子 Widget 是受父 Widget 的约束限制的,超出父 Widget 的部分一般会被截掉。如果想子 Widget 不受父 Widget 的限制,可以使用 OverflowBox ,它是一个溢出 Widget ,可以使用与父 Widget 不同的约束。其构造方法如下:

const OverflowBox({
  Key key,
  //AlignmentGeometry类型可选命名参数,如何在父级范围内对齐子Widget,使用Alignment
  this.alignment = Alignment.center,
  //double类型可选命名参数,最小宽度,不设置(默认值),使用父级约束
  this.minWidth,
  //double类型可选命名参数,最大宽度,不设置(默认值),使用父级约束
  this.maxWidth,
  //double类型可选命名参数,最小高度,不设置(默认值),使用父级约束
  this.minHeight,
  //double类型可选命名参数,最大高度,不设置(默认值),使用父级约束
  this.maxHeight,
  //Widget类型可选命名参数,要显示的Widget
  Widget child,
})

使用如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        color: Colors.yellow,
        height: 200,
        width: 400,
        child: OverflowBox(             //OverflowBox
          minHeight: 100,   
          maxHeight: 300,
          minWidth: 100,
          maxWidth: 300,
          alignment: Alignment.topRight,
          child: Container(
            color: Colors.red,
          ),
        ),
      )
    );
  }
}

效果如下:


2020325929.jpg

九、Offstage Widget

在开发中,有时候需要根据需要来对某个 Widget 进行显示或隐藏,就可以使用 Offstage 。当 Offstage 设置为隐藏时,其不接收任何事件,也不占用父级的任何空间。但如果在 Offstage 中有动画执行,即便其为隐藏状态,动画都会在后台继续执行,会消耗电量和 CPU 。其构造方法如下:

const Offstage({
  Key key, 
  //bool类型可选命名参数,是否隐藏子Widget
  this.offstage = true, 
  //Widget类型可选命名参数,要显示或隐藏的Widget
  Widget child 
})

使用如下:

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("HomePage"),
      ),
      body: Container(
        color: Colors.yellow,
        height: 200,
        width: 400,
        child:  Offstage(                   //Offstage
          offstage: false,       //当设置为true时,在界面上不会显示Text
          child: Text("Offstage"),
        )
      )
    );
  }
}

相关文章

  • Flutter-flutter基础之组件基础(八)

    一、Stack Widget Stack Widget 可以用来设置多个子 Widget ,这些子 Widget ...

  • 本博客文章阅读指南

    分类具体文章Android 基础知识篇四大组件Android 基础知识1:四大组件之 ActivityAndroi...

  • UGUI(一)【唐老狮】六大基础组件,三大基础控件

    Unity中的UI系统之UGUI [toc] 概述 六大基础组件 六大基础组件概述Canvas画布Canvas S...

  • Android基础之基础组件

    1.Activity 说下Activity的生命周期? 答: onStart()和onResume()/onPau...

  • React Native基础之Image

    React Native基础之Image Image组件 在React Native中,Image组件是用来...

  • 组件化流程

    组件化创建大致步骤,以项目、基础组件为例 1、创建项目、基础组件远程仓库 创建项目远程仓库,基础组件远程仓库如下 ...

  • DataPicker

    Android基础:Date & Time组件(上)Android基础:Date & Time组件(下)

  • iOS - 基础笔记

    总结一些平常需要注意的点: 一、基础组件二、组件操作三、布局四、基础模式五、网络六、线程七、数据存储八、多媒体九、...

  • Angular组件篇

    Angular组件 一:组件基础 1:什么是组件? 组件(Component)是构成Angular应用的基础和核心...

  • vue命名规范

    自用vue变量命名规范 props 驼峰式命名 事件 组件 组件文件 基础组件名 基础组件名 name Pasca...

网友评论

    本文标题:Flutter-flutter基础之组件基础(八)

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