I tried to make a ListView that can slide left and right, the item is SingleChildScrollView, InheritedData used to listener, and encountered the following problem:
Looking up a deactivated widget's ancestor is unsafe.
At this point the state of the widget's element tree is no longer stable.
To safely refer to a widget's ancestor in its dispose() method, save a reference to the ancestor by calling dependOnInheritedWidgetOfExactType() in the widget's didChangeDependencies() method.
When the exception was thrown, this was the stack
#0 Element._debugCheckStateIsActiveForAncestorLookup.<anonymous closure>
#1 Element._debugCheckStateIsActiveForAncestorLookup
#2 Element.dependOnInheritedWidgetOfExactType
#3 InheritedData.of
#4 SlideMenuItem.build.<anonymous closure>
...
In order to facilitate the view of the problem, I write the code in the same dart file, the specific implementation is as follows:
import 'package:flutter/material.dart';
typedef SlideMenuBuilder = Widget Function(BuildContext context, int index);
typedef TouchDownCallback = void Function(Offset offset);
class SwipeMemuWidget extends StatefulWidget {
final List<Widget> child;
final SlideMenuBuilder builder;
final int itemCount;
const SwipeMemuWidget({Key key, this.child, this.builder, this.itemCount})
: super(key: key);
@override
State<StatefulWidget> createState() {
return _SwipeMenuWidgetState();
}
}
class _SwipeMenuWidgetState extends State<SwipeMemuWidget> {
Offset tapDownOffset;
@override
Widget build(BuildContext context) {
return InheritedData(
tapDownOffset: tapDownOffset,
child: Listener(
onPointerDown: (downEvent) {
setState(() {
tapDownOffset = downEvent.position;
});
},
child: ListView.builder(
itemCount: widget.itemCount, itemBuilder: widget.builder),
));
}
}
class InheritedData extends InheritedWidget {
final Offset tapDownOffset;
InheritedData({@required this.tapDownOffset, Widget child})
: super(child: child);
static InheritedData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<InheritedData>();
}
@override
bool updateShouldNotify(InheritedData old) => true;
}
class SlideMenuItem extends StatelessWidget {
SlideMenuItem({this.menuWidth, this.showWidth = 750, this.child, this.menus});
final Widget child;
final List<Widget> menus;
final double menuWidth;
final double showWidth;
_buildChildren(BuildContext context) {
List<Widget> childrenWidget = List<Widget>();
childrenWidget.add(Container(
width: showWidth,
child: child,
));
childrenWidget.addAll(menus.map((e) => Container(
color: Colors.red,
child: e,
)));
return childrenWidget;
}
@override
Widget build(BuildContext context) {
bool isAnimated = false;
ScrollController controller = ScrollController();
WidgetsBinding.instance.addPostFrameCallback((duration) {
Offset tapDownOffset = InheritedData.of(context).tapDownOffset;
if (tapDownOffset != null && controller.hasClients) {
RenderBox renderBox = context.findRenderObject();
Offset myOffset = renderBox.localToGlobal(Offset(0, 0));
Size mySize = renderBox.size;
if (controller.offset > 0 &&
(showWidth - controller.offset > tapDownOffset.dx ||
myOffset.dy > tapDownOffset.dy ||
myOffset.dy + mySize.height < tapDownOffset.dy)) {
isAnimated = true;
controller
.animateTo(0,
duration: Duration(milliseconds: 100), curve: Curves.linear)
.then((v) {
isAnimated = false;
});
}
}
});
return Listener(
onPointerUp: (upEvent) {
if (isAnimated) return;
if (controller.offset < menuWidth / 5) {
controller.animateTo(0,
duration: Duration(milliseconds: 100), curve: Curves.linear);
} else {
controller.animateTo(menuWidth,
duration: Duration(milliseconds: 100), curve: Curves.linear);
}
},
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
controller: controller,
child: IntrinsicHeight(
child: Row(
children: _buildChildren(context),
),
),
));
}
}
Please help me, thanks very much!
question from:
https://stackoverflow.com/questions/65649308/flutterlooking-up-a-deactivated-widgets-ancestor-is-unsafe 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…