화면에 위젯의 크기 / 위치를 얻으려면, 당신이 사용할 수있는 GlobalKey
자사 얻기 위해 BuildContext
다음을 찾을 수RenderBox
해당 위젯의 전역 위치와 렌더링 된 크기를 포함 할 특정 위젯 있습니다.
주의해야 할 사항은 하나뿐입니다. 위젯이 렌더링되지 않으면 해당 컨텍스트가 존재하지 않을 수 있습니다. 문제를 일으킬 수있는ListView
위젯이 잠재적으로 표시되는 경우에만 렌더링되므로 가 발생할 수 있습니다.
또 다른 문제는 위젯이 아직 렌더링되지 않았기 때문에 호출 RenderBox
중에 위젯을 가져올 수 없다는 build
것입니다.
하지만 빌드하는 동안 크기가 필요합니다! 어떡해?
거기 캔 도움말 위젯 하나의 멋진는 다음과 같습니다 Overlay
과OverlayEntry
. 다른 모든 것 위에 위젯을 표시하는 데 사용됩니다 (스택과 유사).
그러나 가장 멋진 것은 그들이 다른 build
흐름 에 있다는 것입니다 . 그들은 이후 에 지어 졌습니다. 일반 위젯 됩니다.
그것은 하나의 멋진 의미 OverlayEntry
를 가지고 있습니다 : 실제 위젯 트리의 위젯에 따라 크기를 가질 수 있습니다.
괜찮아. 그러나 OverlayEntry는 수동으로 다시 빌드 할 필요가 없습니까?
예, 그렇습니다. 그러나 알아 두어야 할 또 다른 사항이 있습니다. ScrollController
, a에 전달 된 Scrollable
,는 AnimationController
.
당신이 결합 할 수있는 수단 AnimatedBuilder
A를을 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) {
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();