Para obtener el tamaño / posición de un widget en la pantalla, puede usar GlobalKeypara obtenerlo BuildContexty luego encontrar el RenderBoxde ese widget específico, que contendrá su posición global y tamaño renderizado.
Solo una cosa a tener en cuenta: ese contexto puede no existir si el widget no se representa. Lo que puede causar un problema ListViewya que los widgets se procesan solo si son potencialmente visibles.
Otro problema es que no puede obtener un widget RenderBoxdurante la buildllamada, ya que aún no se ha renderizado.
¡Pero necesito el tamaño durante la construcción! ¿Que puedo hacer?
Hay un widget genial que puede ayudar: Overlayy es OverlayEntry. Se utilizan para mostrar widgets encima de todo lo demás (similar a la pila).
Pero lo mejor es que están en un buildflujo diferente ; se construyen después de los widgets normales.
Eso tiene una implicación genial: OverlayEntrypuede tener un tamaño que depende de los widgets del árbol de widgets real.
Bueno. Pero, ¿no es necesario reconstruir OverlayEntry manualmente?
Ellos si. Pero hay otra cosa a tener en cuenta:, ScrollControllerpasado a Scrollable, es un similar escuchable a AnimationController.
Lo que significa que podría combinar un AnimatedBuildercon un ScrollController, tendría el efecto encantador de reconstruir su widget automáticamente en un pergamino. Perfecto para esta situación, ¿verdad?
Combinando todo en un ejemplo:
En el siguiente ejemplo, verá una superposición que sigue a un widget en el interior ListViewy comparte la misma altura.
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();
},
);
}
}
Nota :
Cuando navegue a una pantalla diferente, llame a seguir, de lo contrario, permanecerá visible.
sticky.remove();