【问题标题】:How to get child widget size for animation values in parent如何获取父级中动画值的子级小部件大小
【发布时间】:2019-09-18 20:43:48
【问题描述】:

随着 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是初始动画begin:的值,//2是中间停止的值,// overall height是动画end:的值。只是为了解释。

至少:我在其中使用states_rebuilder

【问题讨论】:

    标签: flutter dart


    【解决方案1】:

    除非它是一个常量,否则我们只能在它被渲染后获取它的大小。 我们可以使用 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;
      }
    }
    

    【讨论】:

    • 这听起来很有趣!非常感谢,我会实施这个以便更好地理解。
    • 这只有在值(一段时间)发生变化时才有效?在这种情况下,我的值​​ heigt 是硬编码的,可能永远不会更改,但我想通过代码获取 height 以便于维护,而不是为所有这些设置多个常量。
    • 这两种情况都适用。如果将高度设置为 200,则在渲染后,它也会返回高度等于 200。您应该注意,当它进入屏幕并渲染时,它将返回小部件的实际大小。
    • 好的,我会在接下来的几天里实现这个。谢谢
    • 这也解决了其他一些问题,所以我想将此标记为已接受的答案。谢谢,干得真好!
    【解决方案2】:

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

    class ChildSizeNotifier extends StatelessWidget {
      final ValueNotifier<Size> notifier = ValueNotifier(const Size(0, 0));
      final Widget Function(BuildContext context, Size size, Widget child) builder;
      final Widget child;
      UjChildSizeNotifier({
        Key key,
        @required this.builder,
        this.child,
      }) : super(key: key) {}
    
      @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');
      },
    )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-27
      • 1970-01-01
      • 1970-01-01
      • 2020-05-12
      • 2011-09-03
      • 1970-01-01
      • 2017-05-24
      • 1970-01-01
      相关资源
      最近更新 更多