前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【- Flutter 组件篇 285 -】 CustomSingleChildLayout 通用单子布局

【- Flutter 组件篇 285 -】 CustomSingleChildLayout 通用单子布局

作者头像
张风捷特烈
发布2020-05-26 15:27:25
2.1K0
发布2020-05-26 15:27:25
举报
一、认识组件
1. CustomSingleChildLayout组件介绍

可容纳一个子组件,并指定代理类对子组件进行排布。代理类可获取父容器区域和子组件的区域大小,及区域约束情况。

代码语言:javascript
复制
名称:       CustomSingleChildLayout  通用单子排布
类型:       布局型
重要性:     ☆☆☆
相关组件:   【Align】、【FractionallySizedBox】、【CustomMultiChildLayout】  
家族:       RenderObjectWidget
                |--- SingleChildRenderObjectWidget
                    |--- CustomSingleChildLayout
复制代码

二、组件测试
1. 测试环境:

这里父容器使用11灰的300*200的盒子,子组件为不设宽高的橙色Container。 如下: 默认的约束条件,会使橙色Container伸展占满父容器。

代码语言:javascript
复制
class CustomSingleChildLayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 200,
      color: Colors.grey.withAlpha(11),
      child:nContainer(
          color: Colors.orange,
      ),
    );
  }
}
复制代码

2. 认识CustomSingleChildLayout

CustomSingleChildLayout容纳一个child,且需要一个抽象代理类SingleChildLayoutDelegate Flutter并没有提供可用的实现类,所以只能自定义_TolySingleChildLayoutDelegate

代码语言:javascript
复制
class CustomSingleChildLayoutDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      width: 300,
      height: 200,
      color: Colors.grey.withAlpha(11),
      child: CustomSingleChildLayout(
        delegate: _TolySingleChildLayoutDelegate(),
        child: Container(
          color: Colors.orange,
        ),
      ),
    );
  }
}
复制代码

  • SingleChildLayoutDelegate必须实现shouldRelayout方法,可重写:
  • Size getSize(BoxConstraints): 可获取父容器约束条件
  • Offset getPositionForChild(Size, Size) 可获取父子组件的区域,返回子组件偏移量
  • BoxConstraints getConstraintsForChild(BoxConstraints)可获取父容器约束条件,并返回新的约束条件
代码语言:javascript
复制
class _TolySingleChildLayoutDelegate extends SingleChildLayoutDelegate {
  @override
  bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
    return true;
  }

  @override
  Size getSize(BoxConstraints constraints) {
    print('----getSize:----constraints:$constraints----');
    return super.getSize(constraints);
  }

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    print('----size:$size----childSize:$childSize----');
    return super.getPositionForChild(size, childSize);
  }

  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    print('----getConstraintsForChild:----constraints:$constraints----');
    return super.getConstraintsForChild(constraints);
  }
}
复制代码

看一下运行打印结果:

代码语言:javascript
复制
I/flutter (28366): ----getSize:----constraints:BoxConstraints(w=300.0, h=200.0)----
I/flutter (28366): ----getConstraintsForChild:----constraints:BoxConstraints(w=300.0, h=200.0)----
I/flutter (28366): ----size:Size(300.0, 200.0)----childSize:Size(300.0, 200.0)----
复制代码
3.使用新的区域约束

getConstraintsForChild可以根据原约束区域返回新的约束区域。如下:

代码语言:javascript
复制
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
  print('----getConstraintsForChild:----constraints:$constraints----');
  return BoxConstraints(
    maxHeight: constraints.maxHeight/2,
    maxWidth: constraints.maxWidth/2,
    minHeight: constraints.maxHeight/4,
    minWidth: constraints.maxWidth/4,
  );
}
复制代码

4. 子组件的偏移
  • Offset getPositionForChild(Size, Size) 可获取父、子组件的区域,返回子组件偏移量 如下,在刚才的基础上,可以通过偏移让子组件到容器的右上角。

代码语言:javascript
复制
@override
Offset getPositionForChild(Size size, Size childSize) {
  print('----size:$size----childSize:$childSize----');
  return Offset(size.width/2,0 );
}
复制代码

三、CustomSingleChildLayout能干嘛?

从上面可以看出,使用CustomSingleChildLayout可以获取父组件和子组件的布局区域。并可以对子组件进行盒约束偏移定位。一句话来说用于排布一个组件。

1. 控制偏移的代理类

传入一个Offset对象控制子组件的偏移。

代码语言:javascript
复制
class _OffSetDelegate extends SingleChildLayoutDelegate {
  final Offset offset;
  
  _OffSetDelegate({this.offset = Offset.zero});

  @override
  bool shouldRelayout(_OffSetDelegate oldDelegate) =>
      offset != oldDelegate.offset;

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    return offset;
  }
}
复制代码

2. 封装类OffSetWidget

你可以直接用CustomSingleChildLayout组件,但为了方便使用,一般都会进行封装使用 下面的OffSetWidget组件可以实现子组件相对于父组件的偏移。

代码语言:javascript
复制
class OffSetWidget extends StatelessWidget {
  final Offset offset;
  final Widget child;

  OffSetWidget({this.offset = Offset.zero, this.child});

  @override
  Widget build(BuildContext context) {
    return CustomSingleChildLayout(
      delegate: _OffSetDelegate(offset: offset),
      child: child,
    );
  }
}
复制代码

3. OffSetWidget使用

这样就可以让子组件在父组件中发生相对偏移。 简约派代表:"等等...老子看了半天,你给我个简易版的Padding?还花里胡哨的。" 兄台莫急,且往下看。

代码语言:javascript
复制
class OffSetWidgetDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
        width: 300,
        height: 100,
        alignment: Alignment.topRight,
        color: Colors.grey.withAlpha(11),
        child: OffSetWidget(
          offset: Offset(20, 20),
          child: Icon(Icons.android, size: 30,color: Colors.green,),
        ));
  }
}
复制代码

这里最大的优势是: Offset支持负偏移

代码语言:javascript
复制
child: OffSetWidget(
   offset: Offset(-20, 20),
   child: Icon(Icons.android, size: 30,color: Colors.green,),
));
复制代码

4. 方向版

通过动态计算,可以锁定访问进行偏移,如下: 这样就像Position的能力,但Position有必须用于Stack的现在。 而OffSetWidget随意 并且支持负偏移

代码语言:javascript
复制
class OffSetWidget extends StatelessWidget {
  final Offset offset;
  final Widget child;
  final Direction direction;

  OffSetWidget({this.offset = Offset.zero,
      this.child,
      this.direction = Direction.topLeft});

  @override
  Widget build(BuildContext context) {
    return CustomSingleChildLayout(
      delegate: _OffSetDelegate(offset: offset, direction: direction),
      child: child,
    );
  }
}

enum Direction { topLeft, topRight, bottomLeft, bottomRight }

class _OffSetDelegate extends SingleChildLayoutDelegate {
  final Offset offset;
  final Direction direction;

  _OffSetDelegate(
      {this.offset = Offset.zero, this.direction = Direction.topLeft});

  @override
  bool shouldRelayout(_OffSetDelegate oldDelegate) =>
      offset != oldDelegate.offset;

  @override
  Offset getPositionForChild(Size size, Size childSize) {
    var w = size.width;
    var h = size.height;
    var wc = childSize.width;
    var hc = childSize.height;

    switch (direction) {
      case Direction.topLeft:
        return offset;
      case Direction.topRight:
        return offset.translate(w - wc - offset.dx * 2, 0);
      case Direction.bottomLeft:
        return offset.translate(0, h - hc - offset.dy * 2);
      case Direction.bottomRight:
        return offset.translate(w - wc - offset.dx * 2, h - hc - offset.dy * 2);
    }
    return offset;
  }
}
复制代码

CustomSingleChildLayout组件的用法还是比较简单的。上面代码只是简单演示一下使用方式,也许并不是太实用。Positioned组件可以实现定位,SizedOverflowBox组件可以实现溢出。 不过当你遇到对某一个组件约束或定位困难时,CustomSingleChildLayout也许可以帮到你。


本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020年05月26日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、认识组件
    • 1. CustomSingleChildLayout组件介绍
    • 二、组件测试
      • 1. 测试环境:
        • 2. 认识CustomSingleChildLayout
          • 3.使用新的区域约束
            • 4. 子组件的偏移
            • 三、CustomSingleChildLayout能干嘛?
              • 1. 控制偏移的代理类
                • 2. 封装类OffSetWidget
                  • 3. OffSetWidget使用
                    • 4. 方向版
                    相关产品与服务
                    容器服务
                    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
                    领券
                    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档