RenderEditable necesita pasar por el layout antes del hit testing
El hit testing de RenderEditable requiere información adicional que solo está disponible después del layout.
Resumen
#Las instancias de RenderEditable deben tener el layout hecho antes de procesar el hit
testing. Intentar realizar un hit-test en un objeto RenderEditable antes del layout
da como resultado una aserción como la siguiente:
Failed assertion: line 123 pos 45: '!debugNeedsLayout': is not true.
Contexto
#Para soportar gesture recognizers en texto seleccionable, el
RenderEditable requiere la información de layout de sus
text spans para determinar qué text span recibe el
evento de puntero. (Antes de este cambio, los objetos RenderEditable
no tenían en cuenta su texto al evaluar los hit tests).
Para implementar esto, el layout se convirtió en un requisito previo para realizar
el hit testing en un objeto RenderEditable.
En la práctica, esto rara vez es un problema. La librería de widgets asegura que el layout se realice antes de cualquier hit test en todos los render objects. Es probable que este problema solo se vea en código que interactúa directamente con render objects, por ejemplo en pruebas de render objects personalizados.
Guía de migración
#Si ves el error de aserción '!debugNeedsLayout': is not true
al realizar un hit test a RenderEditable,
realiza el layout del RenderEditable antes de hacerlo.
Código antes de la migración:
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
void main() {
test('attach and detach correctly handle gesture', () {
final RenderEditable editable = RenderEditable(
textDirection: TextDirection.ltr,
offset: ViewportOffset.zero(),
textSelectionDelegate: FakeEditableTextState(),
startHandleLayerLink: LayerLink(),
endHandleLayerLink: LayerLink(),
);
final PipelineOwner owner = PipelineOwner(onNeedVisualUpdate: () {});
editable.attach(owner);
// This throws an assertion error because
// the RenderEditable hasn't been laid out.
editable.handleEvent(const PointerDownEvent(),
BoxHitTestEntry(editable, const Offset(10, 10)));
editable.detach();
});
}
class FakeEditableTextState extends TextSelectionDelegate {
@override
TextEditingValue textEditingValue;
@override
void hideToolbar() {}
@override
void bringIntoView(TextPosition position) {}
}
Código después de la migración:
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/material.dart';
void main() {
test('attach and detach correctly handle gesture', () {
final RenderEditable editable = RenderEditable(
textDirection: TextDirection.ltr,
offset: ViewportOffset.zero(),
textSelectionDelegate: FakeEditableTextState(),
startHandleLayerLink: LayerLink(),
endHandleLayerLink: LayerLink(),
);
// Lay out the RenderEditable first.
editable.layout(BoxConstraints.loose(const Size(1000.0, 1000.0)));
final PipelineOwner owner = PipelineOwner(onNeedVisualUpdate: () {});
editable.attach(owner);
editable.handleEvent(const PointerDownEvent(),
BoxHitTestEntry(editable, const Offset(10, 10)));
editable.detach();
});
}
class FakeEditableTextState extends TextSelectionDelegate {
@override
TextEditingValue textEditingValue;
@override
void hideToolbar() {}
@override
void bringIntoView(TextPosition position) {}
}
Timeline
#Introducido en la versión: 1.18.0
En la versión estable: 1.20
Referencias
#Documentación de la API:
Problema relevante:
- Issue 43494: SelectableText.rich usado junto con TapGestureRecognizer no funciona
PR relevante:
A menos que se indique lo contrario, la documentación de este sitio refleja Flutter 3.44.0. Página actualizada por última vez el 2026-05-05. Ver código fuente oreportar un problema.