画面上のウィジェットのサイズ/位置を取得するには、ウィジェットGlobalKey
を取得しBuildContext
てRenderBox
、その特定のウィジェットのを検索します。これには、グローバルな位置とレンダリングされたサイズが含まれます。
注意すべき点が1つだけあります。ウィジェットがレンダリングされていない場合、そのコンテキストは存在しない可能性があります。ListView
ウィジェットは潜在的に表示されている場合にのみレンダリングされるため、問題が発生する可能性があります。
もう1つの問題は、ウィジェットがまだレンダリングされていないため、呼び出しRenderBox
中にウィジェットを取得できないことですbuild
。
しかし、ビルド中にサイズを調整する必要があります!私に何ができる?
役立つことができる1つのクールなウィジェットがあります:Overlay
そしてそのOverlayEntry
。それらは、他のすべての上にウィジェットを表示するために使用されます(スタックと同様)。
しかし、最もクールなことは、それらが異なるbuild
フロー上にあることです。それらは通常のウィジェットの後に構築されます。
これには、非常に優れた意味が1つありOverlayEntry
ます。サイズは、実際のウィジェットツリーのウィジェットに依存する可能性があります。
はい。しかし、OverlayEntryを手動で再構築する必要はありませんか?
はい、彼らはやる。ただしScrollController
、注意すべきもう1つのことがあります。に渡されるScrollable
、は、に似たリスナブルAnimationController
です。
あなたはどちら組み合わせることができ意味AnimatedBuilder
を持つがScrollController
、それはスクロールに自動的にウィジェットを再構築するために素敵な効果を持っているでしょう。この状況に最適ですよね?
すべてを1つの例にまとめます。
次の例では、内部のウィジェットに続き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) {
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();