一统天下 flutter - widget 容器类(只能有一个子): CustomSingleChildLayout - 自定义单组件布局

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

一统天下 flutter - widget 容器类(只能有一个子): CustomSingleChildLayout - 自定义单组件布局

示例如下:

lib\widget\container\custom_single_child_layout.dart

/*
 * CustomSingleChildLayout - 自定义单组件布局
 *
 * 注:约束是从上向下传递的,尺寸是从下向上传递的
 */

import 'package:flutter/material.dart';
import 'package:flutter_demo/helper.dart';

class CustomSingleChildLayoutDemo extends StatefulWidget {
  const CustomSingleChildLayoutDemo({Key? key}) : super(key: key);

  @override
  _CustomSingleChildLayoutDemoState createState() => _CustomSingleChildLayoutDemoState();
}

class _CustomSingleChildLayoutDemoState extends State<CustomSingleChildLayoutDemo> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("title"),),
      backgroundColor: Colors.orange,
      /// 自定义布局
      body: CustomSingleChildLayout(
        /// 通过指定的 delegate 实现具体的布局
        delegate: _MySingleChildLayoutDelegate(),
        /// 通过 LayoutId 指定需要布局的组件的 id
        child: Container(
          width: 200,
          height: 200,
          color: Colors.red,
        ),
      ),
    );
  }
}

class _MySingleChildLayoutDelegate extends SingleChildLayoutDelegate {

  /// 用于根据 CustomSingleChildLayout 自己的约束,决定 CustomSingleChildLayout 的子的约束
  /// constraints 为 CustomSingleChildLayout 的父传给 CustomSingleChildLayout 的约束
  /// 返回值为 CustomSingleChildLayout 传给子的约束
  @override
  BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
    log("getConstraintsForChild constraints:$constraints");
    var childConstraints = BoxConstraints(minWidth: 0, minHeight: 0, maxWidth: 100, maxHeight: constraints.maxHeight);
    return childConstraints;
  }

  /// 用于根据 CustomSingleChildLayout 自己的尺寸以及 CustomSingleChildLayout 的子的尺寸,决定 CustomSingleChildLayout 的子的位置
  /// size 为 CustomSingleChildLayout 的尺寸
  /// childSize 为 CustomSingleChildLayout 的子的尺寸
  /// 返回值为 CustomSingleChildLayout 的子的位置
  @override
  Offset getPositionForChild(Size size, Size childSize) {
    log("getPositionForChild size:$size, childSize:$childSize");
    var dx = (size.width - childSize.width) / 2;
    var dy = (size.height - childSize.height) / 2;
    return Offset(dx, dy);
  }

  /// 如果之后 widget 重新 build 了,就会执行到这里
  /// 一般通过判断 _MySingleChildLayoutDelegate 新旧实例的与 UI 相关的参数是否发生变化来决定是否需要重新布局
  @override
  bool shouldRelayout(covariant _MySingleChildLayoutDelegate oldDelegate) {
    return true;
  }

  /// constraints 为 SingleChildLayoutDelegate 的父传给 SingleChildLayoutDelegate 的约束
  /// 返回值为 SingleChildLayoutDelegate 根据约束决定的自己的尺寸
  @override
  Size getSize(BoxConstraints constraints) {
    var size = super.getSize(constraints);
    log('getSize constraints:$constraints, size:$size');
    return size;
  }
}

源码 https://github.com/webabcd/flutter_demo
作者 webabcd

posted @ 2023-04-27 15:22  webabcd  阅读(59)  评论(0编辑  收藏  举报