要获取屏幕上小部件的大小/位置,可以使用
GlobalKey使其获取
BuildContext然后找到该
RenderBox特定小部件的,其中将包含其全局位置和渲染的大小。
只需注意一件事:如果未呈现小部件,则该上下文可能不存在。
ListView仅当窗口小部件可能可见时才渲染它们,这可能会导致问题。
另一个问题是,由于尚未渲染小部件,因此您
RenderBox在
build通话期间无法获得小部件的。
但是在构建期间我需要大小! 我能做什么?
有一个很酷的小部件可以帮助您:
Overlay及其及其
OverlayEntry。它们用于在其他所有内容(类似于堆栈)的顶部显示小部件。
但最酷的是,它们的
build流向不同。它们是 在 常规小部件 之后 构建的。
这具有一种超酷的含义:
OverlayEntry可以具有取决于实际窗口小部件树的窗口小部件的大小。
好的。 但是,OverlayEntry不需要手动重建吗?
是的,他们有。但是还有另一件事要注意:
ScrollController传递给
Scrollable,与相似,是可收听的
AnimationController。
这意味着您可以将
AnimatedBuilder和组合使用
ScrollController,这将具有在滚动条上自动重建窗口小部件的可爱效果。非常适合这种情况,对吗?
将所有内容组合为示例:
在下面的示例中,您将看到一个覆盖,该覆盖在其内部的小部件之后
ListView并具有相同的高度。
import 'package:flutter/material.dart';import 'package:flutter/scheduler.dart';class MyHomePage extends StatefulWidget { const MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> { final controller = ScrollController(); OverlayEntry sticky; GlobalKey stickyKey = GlobalKey(); @override void initState() { if (sticky != null) { sticky.remove(); } sticky = OverlayEntry( builder: (context) => stickyBuilder(context), ); SchedulerBinding.instance.addPostframeCallback((_) { Overlay.of(context).insert(sticky); }); super.initState(); } @override void dispose() { sticky.remove(); super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( body: ListView.builder( controller: controller, itemBuilder: (context, index) { if (index == 6) { return Container( key: stickyKey, height: 100.0, color: Colors.green, child: const Text("I'm fat"), ); } return ListTile( title: Text( 'Hello $index', style: const TextStyle(color: Colors.white), ), ); }, ), ); } Widget stickyBuilder(BuildContext context) { return AnimatedBuilder( animation: controller, builder: (_,Widget child) { final keyContext = stickyKey.currentContext; if (keyContext != null) { // widget is visible final box = keyContext.findRenderObject() as RenderBox; final pos = box.localToGlobal(Offset.zero); return Positioned( top: pos.dy + box.size.height, left: 50.0, right: 50.0, height: box.size.height, child: Material( child: Container( alignment: Alignment.center, color: Colors.purple, child: const Text("^ Nah I think you're okay"), ), ), ); } return Container(); }, ); }}注意事项 :
导航到其他屏幕时,后续通话将保持可见。
sticky.remove();



