有没有办法设置路线的渲染顺序?

时间:2019-05-07 15:58:01

标签: dart flutter flutter-layout

基本上,我想渲染一个ModalRoute,它依赖于其下面路由中的某些小部件。

要实现此目的,我使用的是GlobalKey,我将其附加到较低路径的小部件上:

/// in LOWER route (widget that is in lower route)
@override
Widget build(BuildContext context) {
  return Container(
    key: globalKey,
    child: ..,
  );
}

/// UPPER route (different class!)
/// called using a function on tap in the lower route widget
/// `showModalRoute(globalKey)` 
@override
Widget buildPage(BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
  final renderBox = globalKey.currentContext.findRenderObject() as RenderBox;
  final Size size = renderBox.size;
  return SizedBox(
    width: size.width,
    height: size.height,
    child: ..,
  );
}

我正在尝试使其对方向更改做出响应。方向更改时,下部路径中的小部件会更改大小。 这里的问题是上方路线似乎是在下方路线之前建造的。也许不是这种情况,但是 size 始终是以前的尺寸,即旋转到potrait或反之亦然时得到的景观尺寸,就好像上面的路线是在较低的路线(我的假设)。职位也是如此。我基本上得到了上一个RenderBox

我是否可以通过renderBox.localToGlobal(0, 0)来获取小部件的当前位置?我想我可以通过在buildPage具有新大小之后呈现 GlobalKey 来实现此目的。

1 个答案:

答案 0 :(得分:1)

检查此代码,告诉我它是否按预期工作

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';

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

StreamController<MyWidgetStatus> firstRouteStatus =
    StreamController.broadcast();

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

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with WidgetsBindingObserver {
  GlobalKey _stateKey;
  MyWidgetStatus _status;
  double height;
  double width;

  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    _stateKey = GlobalKey();

    SchedulerBinding.instance.addPostFrameCallback(_calculatePositionOffset);

    super.initState();
  }

  _calculatePositionOffset(_) {
    _status = _getPositions(_stateKey);

    firstRouteStatus.add(_status);
    print("position = ${_status.position}");
  }

  MyWidgetStatus _getPositions(_key) {
    final RenderBox renderBoxRed = _key.currentContext.findRenderObject();
    final position = renderBoxRed.localToGlobal(Offset.zero);
    final height = renderBoxRed.constraints.maxHeight;
    final width = renderBoxRed.constraints.maxWidth;
    return MyWidgetStatus(position: position, width: width, hight: height);
  }

  void didChangeMetrics() {
    print("Metrics changed");
    SchedulerBinding.instance.addPostFrameCallback(_calculatePositionOffset);
    super.didChangeMetrics();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
          child: Icon(Icons.navigate_next),
          onPressed: () {
            _settingModalBottomSheet(context);
          }),
      body: OrientationBuilder(
        builder: (context, orientation) {
          return Center(
            child: LayoutBuilder(
              builder: (context, constraints) => SizedBox(
                    key: _stateKey,
                    height: orientation == Orientation.portrait ? 100.0 : 50,
                    width: orientation == Orientation.portrait ? 50.0 : 100.0,
                    child: Container(
                      color: Colors.red,
                    ),
                  ),
            ),
          );
        },
      ),
    );
  }

  void _settingModalBottomSheet(context) {
    showModalBottomSheet(
        context: context,
        builder: (BuildContext bc) {
          return Scaffold(
            body: StreamBuilder(
              stream: firstRouteStatus.stream,
              builder: (context, AsyncSnapshot<MyWidgetStatus> snapshot) =>
                  snapshot.hasData
                      ? Container(
                          child: Text("Position = ${snapshot.data.position}"),
                        )
                      : Text("No Data"),
            ),
          );
        });
  }
}

class MyWidgetStatus {
  final Offset position;
  final double hight;
  final double width;

  MyWidgetStatus({
    this.position,
    this.hight,
    this.width,
  });
}

编辑:如果您需要在开始时呈现信息,则可以使用BehaviorSubject而不是像本机StreamController这样的

import 'package:rxdart/rxdart.dart';
StreamController<MyWidgetStatus> firstRouteStatus =
   BehaviorSubject();

在编写此行时,还必须在pubspec.yaml中添加RxDart包,它是0.22.0。

rxdart: ^0.22.0