FlutterComponent最佳实践之角对齐

编程之家收集整理的这篇文章主要介绍了FlutterComponent最佳实践之角对齐编程之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

作者:徐宜生

Flutter布局千千万,虽然Box模型相比于原生布局来说,在大部分场景下都是更加方便了,但是有些场景,确实还是ConstraintLayout来的更方便一点,例如下面这个场景:「将不定长度的角标,放置于容器右上角,同时角标中心和容器角顶点对齐」,这其实是一个常见的需求,几乎在UI中的角标场景下都会用到,只不过大部分时候,直接写死一个差不多的偏移量,用Stack就可以实现了,但如果要求特别精准,Flutter的自带Widget就无法满足需求了(通过Key计算的方式就不说了,有点太浪费性能了)。

CustomMultiChildLayout

我们的想法是,传入两个Widget,一个用来做普通的布局,一个用来做角标,角标中心和布局的右上角订单对齐。

所以,先创建CustomMultiChildLayout。

Container(
  height: 300,width: 300,color: Colors.yellow,child: CustomMultiChildLayout(
    delegate: CornerPositionDelegate(),children: [
      LayoutId(
        id: 1,child: Container(
          color: Colors.redAccent,width: 100,height: 100,),LayoutId(
        id: 2,child: Container(
          color: Colors.green,width: 30,height: 30,],)

这些都是基本功了,不啰嗦了。

在delegate中,我们来实现布局逻辑。

class CornerPositionDelegate extends MultiChildLayoutDelegate {
  @override
  void performlayout(Size size) {
    Size size1 = Size.zero,size2 = Size.zero;
    if (hasChild(1)) {
      size1 = layoutChild(1,BoxConstraints.loose(size));
      positionChild(1,Offset.zero);
    }
    if (hasChild(2)) {
      size2 = layoutChild(2,BoxConstraints.loose(size));
      positionChild(2,Offset(0,size1.height));
    }
  }

  @override
  bool shouldRelayout(covariant MultiChildLayoutDelegate oldDelegate) => true;
}

针对每个child,我们来依次布局,通过layoutChild,传入约束,从而获取Size,接下来调用positionChild,为指定id的child进行布局,通过Offset来调整布局的位置。


这里的BoxConstraints直接设置的loose,当然你也可以根据你自己的需求,来设置Tight或者其它具体的值。

上面的代码很简单,就是将child1放置是Offset(0,0)的位置,同时让child2放置到child1的下面,如图所示。

但是我们想让布局居中,然后角标再到布局的右上角,所以进行下调整。

@override
void performlayout(Size size) {
  Size size1 = Size.zero,size2 = Size.zero;
  if (hasChild(1)) {
    size1 = layoutChild(1,BoxConstraints.loose(size));
    positionChild(
      1,Offset(
        (size.width - size1.width) / 2,(size.height - size1.height) / 2,);
  }
  if (hasChild(2)) {
    size2 = layoutChild(2,BoxConstraints.loose(size));
    positionChild(
      2,Offset(
        size.width / 2 + size1.width / 2 - size2.width / 2,size.height / 2 - size1.height / 2 - size2.height / 2,);
  }
}

竟然so easy,因为我们把所有的尺寸信息都拿到了,所以如何布局,那纯粹是数学上的问题了。

但是,CustomMultiChildLayout有两个使用限制:

  • 子元素必须由外界传入,并附带LayoutId,用于标识不同的组件
  • CustomMultiChildLayout本身的尺寸,只能通过重写delegate的getSize函数来确定,认情况下,返回的是constraints.biggest,但无法根据Child尺寸来动态适配

SingleChildRenderObjectWidget

虽然上面的做法可以实现角对齐的效果,但是总感觉怪怪的。

Flutter原生组件中,Align组件是醉接近我们的需求的,它实际上就是一个SingleChildRenderObjectWidget,它的作用就是将它的唯一Child,布局在父容器的指定位置。

所以,我们模仿这个方式,来创建我们的角对齐组件。

Container(
  alignment: Alignment.center,height: 300,child: Container(
    width: 200,height: 200,color: Colors.redAccent,child: CornerPositionAlign(
      child: Container(
        width: 30,color: Colors.green,)

再来创建其它的实现。

class CornerPositionAlign extends SingleChildRenderObjectWidget {
  const CornerPositionAlign({
    Key? key,required Widget child,}) : super(key: key);

  @override
  RenderObject createRenderObject(BuildContext context) => RenderCornerPositionAlignRenderBox();
}

class RenderCornerPositionAlignRenderBox extends RenderBox with RenderObjectWithChildMixin {
  @override
  void performlayout() {}

  @override
  paint(PaintingContext context,Offset offset) {}
}

这里,在RenderBox中,我mixin了一个RenderObjectWithChildMixin,它是和SingleChildRenderObjectWidget搭配使用的,在这个mixin里面,它帮我们写了很多模板代码,例如attach、detach,同时还给我们返回了一个child对象,用来获取这个子组件。

现在我们先什么也不干,就是绘制这个Child,但是performlayout必须要设置size,这个是SingleChildRenderObjectWidget的尺寸,如果不设置,就会报错。

@override
void performlayout() {
  child?.layout(constraints,parentUsesSize: true);
  size = Size(300,300);
}

@override
paint(PaintingContext context,Offset offset) {
  if (child != null) {
    context.paintChild(child!,offset);
  }
}


parentUsesSize:当Child执行layout之后,Parent是否需要获取Child的尺寸,认为false,这个认false是为了优化渲染的性能,大部分场景下,只有Parent Size和Child Size相关联的时候,才需要在Child改变的时候重绘Parent,否则就不需要重绘Parent,从而优化渲染性能。在Child layout之后,如果Parent要获取Child的尺寸,可以通过size = (child as RenderBox).size来获取

所以,接下来,我们需要完成几件事:

  • 父组件本身,占据约束的最大值
  • Child使用自身约束

所以我们得到了这个。

@override
void performlayout() {
  child?.layout(constraints.loosen());
  size = constraints.biggest;
}

接下来,就是调整Offset了,paint中的offset参数,正是当前父容器的尺寸下的Offset,你可以理解为Child相当于Parent的Zero状态。下面修改偏移,不过首先我们需要拿到Child的尺寸信息。

Size childSize = Size.zero;

@override
void performlayout() {
  child?.layout(constraints.loosen(),parentUsesSize: true);
  childSize = (child as RenderBox).size;
  size = constraints.biggest;
}

@override
paint(PaintingContext context,Offset offset) {
  if (child != null) {
    context.paintChild(
      child!,offset +
          Offset(
            size.width - childSize.width / 2,-childSize.height / 2,);
  }
}

效果如下所示。

这样我们就完成了角对齐的布局方式,同时还封装了组件,可以像Align一样使用这个组件来做角对齐的需求。

总结

以上是编程之家为你收集整理的FlutterComponent最佳实践之角对齐全部内容。

如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给好友。

原文地址:https://blog.csdn.net/weixin_61845324

Android开发中获得屏幕的宽度和高度还是比较常用的,在网上找到了很多,在这算是一个总结,以便以后使用。 1.看到的最常见的一种就是一下的这种了 windowManager = getWindowManager();//得到窗口的管
本次课程表应用功能非常丰富,而且非常实用,可以添加学期的课程信息,设置展示的课程页面,设置上下课时间,设置课表的字体大小,更换应用背景图片、显示授课老师。将设置好的课程表导出到手机内,也可以将课程表文件导入应用,还可以通过通讯工具分享课程表。有上下课提醒,上课时手机自动静音,提醒服务后台常驻。具有个性化设置,设置应用主题,还可以查看软件详情。可以说,是一款非常完整出色的课程表应用。
Frida-Dexdump 脱壳工具下载使用以及相关技术介绍
实现注册界面的布局效果,包含用户名,密码,忘记密码,登录等控件
Android App开发实战之实现微信记账本功能(附源码 超详细必看)
前言首先看一下小米中的加载动画是怎么样的,恩恩~~~~虽然只是张图片,因为录制不上全部,很多都是刚一加载就成功了,一点机会都不提供给我,所以就截了一张图,他这个加载动画特点就是左面圆圈会一直转。仿照的效果如下:实现过程这个没有难度,只是学会一个公式就可以,也就是已知圆心,半径,角度,求圆上的点坐标,算出来的结果在这个点绘制一个实心圆即可,下面是自定义Dialog,让其在底部现实,其中的View也是自定义的一个。class MiuiLoadingDialog(conte
作者:徐宜生Flutter布局千千万,虽然Box模型相比于原生布局来说,在大部分场景下都是更加方便了,但是有些场景,确实还是ConstraintLayout来的更方便一点,例如下面这个场景:「将不定长度的角标,放置于容器右上角,同时角标中心和容器角顶点对齐」,这其实是一个常见的需求,几乎在UI中的角标场景下都会用到,只不过大部分时候,直接写死一个差不多的偏移量,用Stack就可以实现了,但如果要求特别精准,Flutter的自带Widget就无法满足需求了(通过Key计算的方式就不说了,有点太浪费性能了.
前言作为 Android 开发,平时和后端聊得最多的除了喝酒就是接口。常用语:Restful 和 WebService,前者现在聊得多,后者以前聊得多。默认含义分别为:Restful:HTTP 协议 和 JSON 格式WebService:特指 Soap 协议 和 XML 格式针对基于 HTTP 协议且格式为 JSON 的 Restful 接口,Android 客户端一般采用 Retrofit + Gson/Moshi 的方案解决。而针对 Soap 协