Flutter不常用组件(三)

IntrinsicHeight

创建一个将其子级大小调整为子级固有高度的小部件。

它有以下几个属性:

  • Key? key:标识键
  • Widget? child:子组件

如果我们有以下布局界面:

Card(
  child: Row(
    children: [
      SizedBox(
        width: 120,
        child: Image.asset(
          "assets/images/hmbb.png",
          fit: BoxFit.cover,
        ),
      ),
      Expanded(
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Text("Hello World" * 40, maxLines: 10),
        ),
      ),
    ],
  ),
)

image

在我们的预想中,左边的图片应该要充满左边,但是我们又没有给这个组件设置高度,所以它无法充满。有两种方法可以实现,一是设置固定高度,二是使用IntrinsicHeight

Card(
  child: IntrinsicHeight(
    child: Row(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        SizedBox(
          width: 120,
          child: Image.asset(
            "assets/images/hmbb.png",
            fit: BoxFit.cover,
          ),
        ),
        Expanded(
          child: Padding(
            padding: const EdgeInsets.all(8.0),
            child: Text("Hello World" * 40, maxLines: 10),
          ),
        ),
      ],
    ),
  ),
)

image

它可以让Row中所有子组件的高度都设置为其中最大的一个值。虽然这个组件效果很不错,但是劲量避免使用。

IntrinsicWidth

创建一个将其子级调整为子级固有宽度的小部件。功能和IntrinsicHeight一个样。

它有以下几个属性:

  • Key? key:标识键
  • double? stepWidth:限制子组件的宽度为该值的倍数
  • double? stepHeight:限制子组件的高度为该值的倍数
  • Widget? child:子组件
Center(
  child: IntrinsicWidth(
    stepHeight: 100,
    stepWidth: 100,
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Container(height: 100, width: 200, color: Colors.red),
        Container(height: 100, width: 300, color: Colors.blue),
        Container(height: 100, width: 200, color: Colors.green),
      ],
    ),
  ),
)

image

InteractiveViewer

支持平移和缩放与其子组件交互的小部件。

有以下几个属性:

  • Key? key:标识键
  • Clip clipBehavior :裁剪方案。默认为Clip.hardEdge
  • bool alignPanAxis:如果为true则不允许对角平移。默认为false
  • EdgeInsets boundaryMargin:边距。默认为EdgeInsets.zero
  • bool constrained:小部件树中此时的正常大小约束是否应用于子级。默认为true
  • double maxScale:最大的缩放倍数。默认为2.5
  • double minScale:最小的缩放倍数。默认为为0.8
  • void Function(ScaleEndDetails)? onInteractionEnd:当用户在小部件上结束平移或缩放手势时调用
  • void Function(ScaleStartDetails)? onInteractionStart:当用户在小部件上开始平移或缩放手势时调用
  • void Function(ScaleUpdateDetails)? onInteractionUpdate:当用户更新小部件上的平移或缩放手势时调用
  • bool panEnabled:是否允许偏移。默认为true
  • bool scaleEnabled:是否允许缩放。默认为true
  • double scaleFactor:确定每次指针滚动要执行的缩放量。默认为200
  • TransformationController? transformationControllerTransformationController对象
  • required Widget child:子组件
Center(
  child: InteractiveViewer(
    clipBehavior: Clip.hardEdge,
    alignPanAxis: false,
    boundaryMargin: EdgeInsets.zero,
    constrained: true,
    maxScale: 2.5,
    minScale: .5,
    onInteractionEnd: (detail) {
      print("End: $detail");
    },
    onInteractionStart: (detail) {
      print("Start: $detail");
    },
    onInteractionUpdate: (detail) {
      print("Update: $detail");
    },
    panEnabled: true,
    scaleEnabled: true,
    scaleFactor: 200.0,
    transformationController: TransformationController(),
    child: SizedBox.expand(child: Image.asset("assets/images/iv.jpg")),
  ),
)

image

需要注意的是,即使我们设置了minScale: .5scaleEnabled: true这两属性,我们依然无法缩小我们的子组件。我们需要将boundaryMargin设置为EdgeInsets.all(double.infinity)(当然,只要设置了数值就行。如果没太多要求,double.infinity是最好的值)。

现在我们就可以愉快的缩小我们的子组件了:

image

MergeableMaterial

ExpansionPanelList是使用该组件实现的,关于该组件的介绍请查看文章Flutter 系统是如何实现ExpansionPanelList的

该组件和BottomNavigationBar一样用来创建底部导航栏。

该组件有以下几个属性:

  • Key? key:标识键
  • Duration? animationDuration:动画持续事件
  • int selectedIndex:当前索引。默认为0
  • List<Widget> destinations:底部选项组件,一般为NavigationDestination
  • void Function(int)? onDestinationSelecteddestinations选择事件
  • Color? backgroundColor:背景颜色
  • double? elevation:海拔高度,轨道的标高或 z 坐标
  • double? height:导航栏的高度
  • NavigationDestinationLabelBehavior? labelBehavior:定义destinations的标签将如何布局以及何时显示
Scaffold(
  appBar: AppBar(title: const Text("NavigationDestination")),
  bottomNavigationBar: NavigationBar(
    animationDuration: null,
    selectedIndex: _index,
    destinations: const [
      NavigationDestination(
        icon: Icon(Icons.home),
        label: 'Home',
      ),
      NavigationDestination(
        icon: Icon(Icons.explore),
        label: 'Explore',
      ),
      NavigationDestination(
        selectedIcon: Icon(Icons.bookmark),
        icon: Icon(Icons.bookmark),
        label: 'Saved',
      ),
    ],
    onDestinationSelected: (index) {
      _index = index;
      _controller.jumpToPage(index);
      setState(() {});
    },
    backgroundColor: null,
    elevation: null,
    height: null,
    labelBehavior: null,
  ),
  body: PageView.builder(
    controller: _controller,
    onPageChanged: (index) {
      _index = index;
      setState(() {});
    },
    itemBuilder: (context, index) => ColoredBox(
      color: Colors.primaries[index % Colors.primaries.length],
    ),
  ),
)

image

用在侧边的导航栏。

该组件有以下几个属性:

  • Key? key:标识键
  • Color? backgroundColor:背景色
  • bool extendedNavigationRail是否应处于扩展状态。默认为false
  • Widget? leading:排在最前面的组件
  • Widget? trailing:排在最后面的组件
  • List<NavigationRailDestination> destinationsNavigationRailDestination对象组
  • int? selectedIndex:当前选择的索引
  • void Function(int)? onDestinationSelected:选择事件
  • double? elevation:海拔高度,轨道的标高或 z 坐标
  • double? groupAlignment:轨道内destinations组的垂直对齐方式。值在 -1.0 和 1.0 之间,0 中心对齐
  • NavigationRailLabelType? labelType:为默认的、未扩展的NavigationRail定义标签的布局和行为
  • TextStyle? unselectedLabelTextStyle:未选中标签的文本样式
  • TextStyle? selectedLabelTextStyle:选中的标签的文本样式
  • IconThemeData? unselectedIconTheme:未选中标签的图标主题
  • IconThemeData? selectedIconTheme:选中的标签的图标主题
  • double? minWidth:最小宽度
  • double? minExtendedWidth:当extendedtrue时的最小宽度
  • bool? useIndicator:是否使用指示器。默认为true
  • Color? indicatorColor:指示器的颜色
Row(
  children: <Widget>[
    NavigationRail(
      backgroundColor: null,
      extended: false,
      leading: const CircleAvatar(
        backgroundImage: AssetImage("assets/images/hmbb.png"),
      ),
      trailing: const Icon(Icons.exit_to_app, color: Colors.blue),
      selectedIndex: _selectedIndex,
      onDestinationSelected: (int index) {
        setState(() {
          _selectedIndex = index;
        });
      },
      elevation: 4,
      groupAlignment: -.9,
      labelType: NavigationRailLabelType.all,
      destinations: const <NavigationRailDestination>[
        NavigationRailDestination(
          icon: Icon(Icons.favorite_border),
          selectedIcon: Icon(Icons.favorite),
          label: Text('First'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.bookmark_border),
          selectedIcon: Icon(Icons.book),
          label: Text('Second'),
        ),
        NavigationRailDestination(
          icon: Icon(Icons.star_border),
          selectedIcon: Icon(Icons.star),
          label: Text('Third'),
        ),
      ],
    ),
    Expanded(
      child: Center(
        child: Text('selectedIndex: $_selectedIndex'),
      ),
    )
  ],
),

image

创建一个以适合工具栏的方式布置其子项的小部件。相当于Row组件有3个子组件,中间的子组件使用了Expanded

该组件有以下几个属性:

  • Key? key:标识键
  • Widget? leading:最前面的组件
  • Widget? middle:中间的组件
  • Widget? trailing:最后面的组件
  • bool centerMiddlemiddle组件是否居中。默认为true
  • double middleSpacing:水平轴上middle组件周围的间距。默认为16.0
SafeArea(
  child: Column(
    children: [
      Container(
        width: double.infinity,
        height: kTextTabBarHeight,
        color: Colors.white,
        child: NavigationToolbar(
          leading: const BackButton(),
          middle: Text(
            "NavigationToolbar",
            style: Theme.of(context).textTheme.titleLarge,
          ),
          trailing: IconButton(
            icon: const Icon(Icons.more_vert),
            onPressed: () {},
          ),
          centerMiddle: false,
          middleSpacing: 16.0,
        ),
      ),
      Expanded(
        child: Center(
          child: Text(
            "使用NavigationToolbar完成的APPBar",
            style: Theme.of(context).textTheme.bodyLarge,
          ),
        ),
      ),
    ],
  ),
)

image

posted @ 2022-12-03 11:14  菠萝橙子丶  阅读(278)  评论(0编辑  收藏  举报