繁体   English   中英

如何获取父级中 animation 值的子小部件大小

[英]How to get child widget size for animation values in parent

虽然 flutter 正在增长,但有很多建议和“方法如何”。 我不确定什么是正确的,因为我对框架真的很陌生。

说,我有以下代码(几乎没有减少):

@override
Widget build(BuildContext context) {
  return GestureDetector(
    // heights are needed here for animation values
      child: Stack(
    children: <Widget>[
      Positioned(
        left: 0,
        right: 0,
        bottom: value,
        child: Column( // overall height
          children: <Widget>[
            Container(height: 60),  // 1
            Container(height: 150), // 2
            Container(height: 200),
          ],
        ),
      ),
    ],
  ));
}

GestureDetector ,我根据其子项的不同高度为一些小部件操作设置动画。

孩子//1//2 (和第三个)的height将在开发时被硬编码,但是,因为有几个这样的元素和自定义小部件,我想自动获取它们。 稍后,总而言之,这更易于维护,因为大多数地方的每个小部件都有一些动画。

所以,我可以使用GlobalKey ,或者BoxConstraints ,但是 - 总而言之 - 如果构建为自定义小部件,那么最便宜的方法是什么?

结束这个问题:在GestureDetector中,我可以在初始布局完成后和每次重建后重建。

我只是不确定哪种方式安全且成本最低(在代码中多次使用这些小部件)。

关于//1//2 : //1是初始 animation begin: value, //2是中间停止的 value, // overall height是 animation end: value。 只是为了解释。

至少:我在所有这些中使用states_rebuilder

除非它是常量,否则我们只能在渲染后获取小部件的大小。 我们可以使用 ValueNotifier 在渲染后发送孩子的大小。

这是它的完整示例。

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ValueNotifier<Size> _size = ValueNotifier<Size>(Size(0, 0));

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("example")
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            ValueListenableBuilder(
              builder: (BuildContext context, Size value, Widget child) {
                return Column(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    Text('Height of the child: ${value.height}'),
                    Text('Width of the child: ${value.width}'),
                    SizeTrackingWidget(
                      child: Container(
                        height: MediaQuery.of(context).size.width*0.4,
                        width:  MediaQuery.of(context).size.width*0.3,
                        color: Colors.red
                      ),
                      sizeValueNotifier: _size,
                    )
                  ],
                );
              },
              valueListenable: _size,
              child: null,
            )
          ],
        ),
      ),
    );
  }
}


class SizeTrackingWidget extends StatefulWidget {
  Widget child;
  ValueNotifier<Size> sizeValueNotifier;
  SizeTrackingWidget({Key key, @required this.sizeValueNotifier, @required this.child}) : super(key: key);
  @override
  _SizeTrackingWidgetState createState() => _SizeTrackingWidgetState();
}

class _SizeTrackingWidgetState extends State<SizeTrackingWidget> {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_){
      _getSize();
    });
  }

  _getSize() {
    RenderBox renderBox = context.findRenderObject();
    widget.sizeValueNotifier.value = renderBox.size;
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

受@Thang Mai 接受的答案的启发,我做了一个类似的无状态解决方案:

class ChildSizeNotifier extends StatefulWidget {
  final Widget Function(BuildContext context, Size size, Widget child) builder;
  final Widget child;
  ChildSizeNotifier({
    Key? key,
    required this.builder,
    this.child,
  }) : super(key: key) {}

  @override
  State<ChildSizeNotifier> createState() => _ChildSizeNotifierState();
}

class _ChildSizeNotifierState extends State<ChildSizeNotifier> {
 final ValueNotifier<Size> _notifier = ValueNotifier(const Size(0, 0));

  @override
  void dispose() {
    _notifier.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    WidgetsBinding.instance.addPostFrameCallback(
      (_) {
        notifier.value = (context.findRenderObject() as RenderBox).size;
      },
    );
    return ValueListenableBuilder(
      valueListenable: notifier,
      builder: builder,
      child: child,
    );
  }
}

像这样使用它

ChildSizeNotifier(
  builder: (context, size, child) {
    // size is the size of the text
    return Text(size.height > 50 ? 'big' : 'small');
  },
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM